题目链接:https://codeforces.com/contest/1034/problem/E。
很精妙的构造。
直接套用$\rm vfk$论文可以得到一个$O(2^nn^2)$的暴力,但是没什么用。。
出题人给出了一个很牛逼的方法:
设$f_{i}=a_i\cdot 4^{cnt(i)},g_{i}=b_i\cdot 4^{cnt(i)}$,$\rm cnt$是二进制下$1$的个数,$4$是模数,模数改一改正确性也不会有问题。
然后把$f,g$或卷积起来得到$h$,$\frac{h_i}{4^{cnt(i)}}\bmod 4$就是答案。
考虑下为什么,这实际上是把每一位都当成了一个小多项式,那么如果没有进位,每一位就是所有${\rm cnt}(x)+{\rm cnt}(y)=i$的答案。
但是由于我们只需要最低位,所以考虑进位也不会有任何影响。
复杂度$O(2^nn)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include<bits/stdc++.h> using namespace std;
#define int long long
void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; }
void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double #define ll long long
#define pii pair<int,int > #define vec vector<int >
#define pb push_back #define mp make_pair #define fr first #define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2.1e6+10; const int inf = 1e9; const lf eps = 1e-8; const int mod = 1e9+7;
#define cnt(x) __builtin_popcount(x)
char s[maxn],t[maxn]; int n,a[maxn],b[maxn];
void fwt(int *r,int op) { for(int i=1;i<1<<n;i<<=1) for(int j=0;j<1<<n;j+=i<<1) for(int k=0;k<i;k++) r[i+j+k]+=r[j+k]*op; }
signed main() { read(n);scanf("%s%s",s,t); for(int i=0;i<1<<n;i++) { a[i]=(1ll<<(cnt(i)<<1))*(s[i]-'0'); b[i]=(1ll<<(cnt(i)<<1))*(t[i]-'0'); } fwt(a,1),fwt(b,1); for(int i=0;i<1<<n;i++) a[i]=a[i]*b[i]; fwt(a,-1); for(int i=0;i<1<<n;i++) putchar(((a[i]>>(cnt(i)<<1))&3)+'0');puts(""); return 0; }
|