[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 }

 

posted @ 2018-04-10 18:06  HocRiser  阅读(275)  评论(0编辑  收藏  举报