[CF1034E]Little C Loves 3 III

Little C Loves 3 III

题解

挺好的做法,想到了还是挺简单的。

首先这个形式我们是很容易想到卷积的,但由于有 j ∣ k = i j|k=i jk=i j & k = 0 j\&k=0 j&k=0两个条件不好直接卷积。
我们可以先考虑到将 j & k = 0 j\&k=0 j&k=0这个条件转化一下,让我们在多项式乘法的过程中可以直接处理掉。
由于最后答案是要 m o d   4 mod\,4 mod4的,设 b i t x bit_{x} bitx表示 x x x中一的个数,将 a i a_{i} ai变为 a i ⋅ 4 b i t i a_{i}\cdot 4^{bit_{i}} ai4biti b i b_{i} bi变成 b i ⋅ 4 b i t i b_{i}\cdot 4^{bit_{i}} bi4biti,再做或卷积乘起来求出 c i c_{i} ci
那么此时的 c i c_{i} ci也应该是 c i ⋅ 4 b i t i c_{i}\cdot 4^{bit_{i}} ci4biti。但由于这是或卷积乘起来的,此处的 c i c_{i} ci包含的不止 4 b i t i 4^{bit_{i}} 4biti
我们观察一下,哪些不止 4 b i t i 4^{bit_{i}} 4biti。很明显,有 b i t j ∣ k + b i t j & k = b i t j + b i t k bit_{j|k}+bit_{j\&k}=bit_{j}+bit_{k} bitjk+bitj&k=bitj+bitk。只有当 j & k = 0 j\&k=0 j&k=0时,才有 b i t j ∣ k = b i t j + b i t k bit_{j|k}=bit_{j}+bit_{k} bitjk=bitj+bitk
所以,当我们将 c i c_{i} ci除去 4 b i t i 4^{bit_{i}} 4biti后, j & k = 0 j\&k=0 j&k=0的在 c i c_{i} ci中是实值,其它的都包含 4 4 4的幂。
此时,我们在模一个 4 4 4,就只有 j & k = 0 j\&k=0 j&k=0的会产生贡献了。
所以,我们只需要改改后做一次FWT就可以了。

时间复杂度 O ( n l o g   n ) O\left(nlog\,n\right) O(nlogn)

源码

注意数组大小,开 2 22 2^{22} 222会MLE。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define MAXN (1<<21)+5
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int lim,n,bit[MAXN],a[MAXN],b[MAXN];
inline void FWTor(LL *A,const int typ){
	for(int k=1;k<=lim;k<<=1)
		for(int i=0;i<lim;i+=(k<<1))
			for(int j=i;j<i+k;j++)
				if(j+k<lim)A[j+k]+=1ll*typ*A[j];
}
LL A[MAXN],B[MAXN];
signed main(){
	read(n);lim=(1<<n);for(int i=1;i<lim;i++)bit[i]=bit[i>>1]+(i&1);
	for(int i=0;i<lim;i++)scanf("%1d",&a[i]),A[i]=(1ll*a[i])<<bit[i]+bit[i];FWTor(A,1);
	for(int i=0;i<lim;i++)scanf("%1d",&b[i]),B[i]=(1ll*b[i])<<bit[i]+bit[i];FWTor(B,1);
	for(int i=0;i<lim;i++)A[i]=A[i]*B[i];FWTor(A,-1);
	for(int i=0;i<lim;i++)printf("%lld",(A[i]>>bit[i]+bit[i])&3);
	return 0;
}


谢谢!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值