题解:P7740 [NOI2021] 机器人游戏
分析
观察题面,发现神秘的样例解释 2,每一句都在告诉我们:对起点集合容斥。
那么就按照这个做法,考虑对于单个机器人的单个位置,它会受到某个起点位置怎样的限制。
容易发现,限制形如
显然每个机器人是独立的,因此我们直接用 bitset 压缩这
::::info[如何得到每个位置受到哪些限制?]
定义一个
设
那么初始
否则如果
否则只有
没有限制的情况不可能,因为每个位置要么被机器人修改要么没有,没有修改那么会受到
做法 1
直接枚举起点集合。
考虑依次填每个机器人的第
考虑使用子集递推减少枚举每一个起点位置的复杂度,设
接下来对于每个起点集合计算
注意初始化时根据集合大小的奇偶性决定是
做法 2
考虑每一位是否作为起点,这样进行 dp。
考虑到最右起点关系到机器人是否会爆炸的特殊性,我们枚举最右起点位置,然后依次考虑每一位是否作为起点。
设最右起点位置为
因此考虑类似滑动窗口的方式 dp:设
同样设
预处理两个数组
考虑转移,就是枚举当前位置是否要作为起点,以及是否有更往前的起点。分讨
注意如果选,起点集合大小的奇偶性会发生改变,因此是转移是减方案数。
综合
我们发现两种做法的复杂度都是
我们发现做法 2 的复杂度和
code
::::success[code]
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7,M=1005;
int n,m,B;
ll pw2[M],pw3[M],f[65536],ans,f2[2][65536][2],ul[65536],vl[65536];
char s[105];
bitset<M> ban[32],R,tmp1,tmp2,tmp3;
struct node{
bitset<M> b[4];
node operator |(const node &x)const{
node y;
for(int i=0;i<4;i++) y.b[i]=b[i]|x.b[i];
return y;
}
ll calc(){
tmp1=R&~((b[0]&b[1])|(b[2]&b[3])),tmp2=tmp1&((b[0]|b[1])&(b[2]|b[3])),tmp3=tmp1^tmp2;
return pw2[tmp2.count()]*pw3[tmp3.count()]%mod;
}
}op[32],lim[65536],tw;
int lowbit(int x){
return x&(-x);
}
ll calc2(node x){
x.b[2].set();
return x.calc();
}
int main(){
cin>>n>>m;
B=n/2;
pw2[0]=pw3[0]=1;
for(int i=1;i<=m;i++){
tw.b[2].set(i);
pw2[i]=pw2[i-1]*2%mod,pw3[i]=pw3[i-1]*3%mod;
}
for(int i=0;i<n;i++){
op[i]=tw;
}
for(int i=1;i<=m;i++){
scanf("%s",s+1);
int len=strlen(s+1),nw=0,tp=2;
for(int j=1;j<=len;j++){
if(s[j]=='R'){
op[nw].b[2].set(i,0);
op[nw].b[tp].set(i);
tp=2;
nw++;
}
else if(s[j]=='1') tp=1;
else if(s[j]=='0') tp=0;
else tp^=1;
}
op[nw].b[2].set(i,0);
op[nw].b[tp].set(i);
for(int j=0;j<n-nw;j++){
ban[j].set(i);
}
}
f[0]=mod-1;
for(int i=1;i<(1<<B);i++){
f[i]=mod-f[i&(i-1)];
}
for(int p=0;p<n;p++){
for(int i=1;i<(1<<B);i++){
int dis=p-__lg(lowbit(i));
if(dis<0) lim[i]=lim[i&(i-1)]|tw;
else lim[i]=lim[i&(i-1)]|op[dis];
}
for(int i=1;i<(1<<B);i++){
R=ban[__lg(i)];
f[i]=f[i]*lim[i].calc()%mod;
}
}
for(int i=1;i<(1<<B);i++){
ans=(ans+f[i])%mod;
}
for(int i=1;i<(1<<n-B);i++){
lim[i]=lim[i&(i-1)]|op[__lg(lowbit(i))];
}
for(int w=B;w<n;w++){
memset(f2,0,sizeof(f2));
f2[1][0][0]=mod-1;
R=ban[w];
for(int i=0;i<(1<<n-w);i++){
ul[i]=lim[i].calc(),vl[i]=calc2(lim[i]);
}
for(int p=0;p<n;p++){
memset(f2[p&1],0,sizeof(f2[p&1]));
for(int i=0;i<(1<<n-w);i++){
for(int op=0;op<2;op++){
int out=i>>(n-w-1)&1;
if(p<w){
int j=(i^(i&1<<n-w-1))<<1|1;
f2[p&1][j][op|out]=(f2[p&1][j][op|out]-f2[p+1&1][i][op]*vl[j]%mod+mod)%mod;
j--;
f2[p&1][j][op|out]=(f2[p&1][j][op|out]+f2[p+1&1][i][op]*vl[j])%mod;
}
else if(p==w){
int j=(i^(i&1<<n-w-1))<<1|1;
f2[p&1][j][op|out]=(f2[p&1][j][op|out]-f2[p+1&1][i][op]*(op|out? vl[j]:ul[j])%mod+mod)%mod;
}
else{
int j=(i^(i&1<<n-w-1))<<1;
f2[p&1][j][op|out]=(f2[p&1][j][op|out]+f2[p+1&1][i][op]*(op|out? vl[j]:ul[j]))%mod;
}
}
}
}
for(int i=0;i<(1<<n-w);i++){
ans=(ans+f2[n-1&1][i][0]+f2[n-1&1][i][1])%mod;
}
}
cout<<ans<<endl;
return 0;
}
::::