[Nescafé41]编码病毒(循环卷积)
题意看起来好麻烦实际上很简单,首先4s可以先bitset暴力一下,听说卡卡就能过:$O(2^{22}+n^2/32)$
1 #include<cstdio> 2 #include<bitset> 3 #include<cstring> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=l; i<=r; i++) 6 using namespace std; 7 8 const int N=100100,inf=0x3f3f3f3f; 9 bitset<N>data,test; 10 int n,m,ans,cost[N],cnt[4194314]; 11 char s[N]; 12 13 int main(){ 14 freopen("virus.in","r",stdin); 15 freopen("virus.out","w",stdout); 16 scanf("%d%d",&m,&n); int t=(1<<m)-1; ans=inf; 17 memset(cost,0x3f,sizeof(cost)); cost[0]=0; 18 rep(i,1,t){ 19 cnt[i]=cnt[i>>1]+(i&1); 20 cost[i%n]=min(cost[i%n],cnt[i]+1); 21 cost[((n-i)%n+n)%n]=min(cost[((n-i)%n+n)%n],cnt[i]); 22 } 23 scanf("%s",s); rep(i,0,n) data[i]=s[i]=='1'; 24 scanf("%s",s); rep(i,0,n) test[i]=s[i]=='1'; 25 for (int i=0; i<n; i++){ 26 if (i) { int j=data[0]; data>>=1; data[n-1]=j; } 27 int j=(data^test).count(); 28 ans=min(ans,min(j,n-j+1)+cost[i]); 29 } 30 printf("%d\n",ans); 31 return 0; 32 }
然后我们观察一下我们的这个暴力到底在做什么事情,发现后面的主循环实际上就是一个类似循环卷积的问题,我们要把它变成真正的卷积。
观察异或真值表:
0 0 0
0 1 1
1 0 1
1 1 0
我们变换一下:把a中0位上的值变成-1,1位上的值变成1,b中相反,于是就有:
0 0 1
0 1 -1
1 0 -1
1 1 1
最后我们将所有结果加1,再除以2,就变成上面的那个表了,这就成功将循环异或变成了循环卷积,直接做即可。
1 #include<cmath> 2 #include<cstdio> 3 #include<complex> 4 #include<cstring> 5 #include<algorithm> 6 #define rep(i,l,r) for (int i=l; i<=r; i++) 7 using namespace std; 8 typedef complex<double> C; 9 const int N=600100,inf=0x3f3f3f3f; 10 const double pi=acos(-1.); 11 char s[N]; 12 int n,m,k,ans,cost[N],rev[N],cnt[4194314],data[N],test[N],c[N]; 13 14 C a[N],b[N]; 15 16 void DFT(C a[],int n,int f){ 17 for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]); 18 for (int i=1; i<n; i<<=1){ 19 C wn=C(cos(pi/i),f*sin(pi/i)); 20 for (int p=i<<1,j=0; j<n; j+=p){ 21 C w=C(1,0); 22 for (int k=0; k<i; k++,w=w*wn){ 23 C x=a[j+k],y=a[i+j+k]*w; a[j+k]=x+y; a[i+j+k]=x-y; 24 } 25 } 26 } 27 if (f==-1) for (int i=0; i<n; i++) a[i].real()/=n; 28 } 29 30 void mul(int test[],int data[],int res[],int m){ 31 int n,L=0; 32 for (n=1; n<=m; n<<=1) L++; 33 for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); 34 for (int i=0; i<n; i++) a[i]=C((double)test[i],0),b[i]=C((double)data[i],0); 35 DFT(a,n,1); DFT(b,n,1); for (int i=0; i<n; i++) a[i]=a[i]*b[i]; DFT(a,n,-1); 36 m/=3; for (int i=0; i<m; i++) res[i]=int(a[i+m-1].real()+0.5); 37 } 38 39 int main(){ 40 freopen("virus.in","r",stdin); 41 freopen("virus.out","w",stdout); 42 scanf("%d%d",&m,&n); int t=(1<<m)-1; ans=inf; 43 memset(cost,0x3f,sizeof(cost)); cost[0]=0; 44 rep(i,1,t){ 45 cnt[i]=cnt[i>>1]+(i&1); 46 cost[i%n]=min(cost[i%n],cnt[i]+1); 47 cost[((n-i)%n+n)%n]=min(cost[((n-i)%n+n)%n],cnt[i]); 48 } 49 scanf("%s",s); for (int i=0; i<n; i++) data[i]=data[i+n]=((s[i]=='1')?1:-1); 50 scanf("%s",s); for (int i=0; i<n; i++) test[n-i-1]=((s[i]=='1')?1:-1); 51 mul(test,data,c,3*n); 52 for (int i=0; i<n; i++) k=(c[i]+n)>>1,ans=min(ans,cost[i]+min(k+1,n-k)); 53 printf("%d\n",ans); 54 return 0; 55 }