CF1034E Little C Loves 3 III
阿新 • • 發佈:2020-10-23
子集卷積, \(len\le 2^{21},0\le a[i],b[i]\le 3,ans\%4\)
即對於 \(i\in[0,2^n-1]\) 求出
\[(\sum_{j|k=i,j\&k=0}a[j]\times b[k])\mod 4 \]看到這題 \(5min\) 莽了個子集卷積上去,MLE on 1
哦, \(64MB\) ,那就壓位!
寫掛了,調了一個下午,終於 調出來了!
然後 TLE on 7
好了,徹底放棄暴力過去的方法
\(\color{black}{\texttt{z}}\color{red}{\texttt{houakngyang}}\)
具體做法是這樣的:設 \(cnt_i\) 表示 \(i\) 的二進位制中 \(1\) 的個數
令 \(a_i=2^{2*cnt_i}*s_i\) (\(s\) 是輸入的字串)
\(b_i\) 同理
然後,直接FWT把兩個東西或起來,乘上 \(\dfrac{1}{2^{2*cnt_i}}\) 輸出 。
為啥這是對的?
\(\color{black}{\texttt{z}}\color{red}{\texttt{houakngyang}}\) 告訴我:考慮當 \(k=i|j\) 時,\(cnt_i+cnt_j\ge cnt_k\)
這有啥用啊?
當 \(i\&j\not=0\) 時,\(\dfrac{cnt_i+cnt_j}{2*cnt_k}>0\) ,\(4^{\frac{cnt_i+cnt_j}{2*cnt_k}}\mod 4=0\) ,不產生貢獻
否則產生的貢獻恰好是題目所求的。
大結論題。。。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef double db; #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i) inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f?x:-x; } int rdc(){ char ch=getchar(); while(!isdigit(ch))ch=getchar(); return ch-'0'; } const int N=1<<21; int n,m; LL a[N],b[N]; void fwt(LL*a,int op){ for(int i=1;i<m;i<<=1) for(int j=0;j<m;j+=i<<1) for(int k=0;k<i;++k) a[i+j+k]+=a[j+k]*op; } signed main(){ m=(1<<(n=read())); for(int i=0;i<m;++i)a[i]=(1ll<<(__builtin_popcount(i)<<1))*rdc(); for(int i=0;i<m;++i)b[i]=(1ll<<(__builtin_popcount(i)<<1))*rdc(); fwt(a,1),fwt(b,1); for(int i=0;i<m;++i)a[i]*=b[i]; fwt(a,-1); for(int i=0;i<m;++i)putchar('0'+((a[i]>>(__builtin_popcount(i)<<1))&3)); puts(""); return 0; }