1. 程式人生 > 實用技巧 >CF1034E Little C Loves 3 III

CF1034E Little C Loves 3 III

CF1034E Little C Loves 3 III

子集卷積, \(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}}\)

告訴我可以 \(O(n\log n)\) ,我深深地感到了我的弱小

具體做法是這樣的:設 \(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;
}