https://codeforces.com/gym/102870
题意:
给定数组a,定义一次操作为对a求异或前缀和数组,求出的数组作为新的a。求a进行k次操作后的值
\(n<=1e5,a_i<=2^{17},k<=1e18\)
解法:
找规律可以发现,不停进行求前缀和操作,a的值会循环变化,循环节是>=n的最小2的幂次,这样就可以将k减小至1e5的级别。
异或操作对于不同数位之间是没有影响的,因此可以将a数组的各数位分离,对于一个数位的数组进行求异或前缀和,就相当于求前缀和最后模2。而对一个长度为n+1的数组求前缀和,可以转化为生成函数来考虑,相当于乘一个生成函数\((1+x+x^2+...+x^n)\),题目要求做k次操作,则相当于对原数组乘一个\((1+x+x^2+...+x^n)^k\),后者可以用FFT套快速幂快速求出,因为最后答案只要取前n+1位,每次多项式相乘只要保留前n+1位即可。
#include<bits/stdc++.h>
typedef long long ll;
typedef double db;
using namespace std;
const db pi=acos(-1.0);
struct cp{
db x,y;
cp(){x=y=0;}
cp(db xx,db yy){x=xx,y=yy;}
};
cp operator + (cp a,cp b){
return cp(a.x+b.x,a.y+b.y);
}cp operator - (cp a,cp b){
return cp(a.x-b.x,a.y-b.y);
}cp operator * (cp a,cp b){
return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
inline void FFT(int n,vector<cp> &a,int t,vector<int> &rev){//迭代版FFT
for(int i=0;i<=n-1;i++)
if(i<rev[i])swap(a[i],a[rev[i]]);
for(int len=1;len<=(n>>1);len<<=1){
cp w1(cos(pi/len),t*sin(pi/len));
for(int i=0;i<=n-(len<<1);i+=(len<<1)){
cp w(1,0);
for(int j=0;j<=len-1;j++){
cp x=a[i+j],y=w*a[i+j+len];
a[i+j]=x+y,a[i+j+len]=x-y;
w=w*w1;
}
}
}
}
void solve(vector<int>&a,vector<int>&b,vector<int>&res){
int n,m;
n=a.size()-1,m=b.size()-1;
int k=1,ci=0;
while(k<=n+m)k<<=1,ci++;
vector<int> rev(k+1,0);
vector<cp> f(k+1),g(k+1);
for(int i=0;i<=n;i++)f[i].x=a[i];
for(int i=0;i<=m;i++)g[i].x=b[i];
for(int i=1;i<=k-1;i++)//二进制翻转
rev[i]=(rev[i>>1]>>1)|((i&1)<<(ci-1));
FFT(k,f,1,rev);
FFT(k,g,1,rev);
for(int i=0;i<=k;i++)
f[i]=f[i]*g[i];
FFT(k,f,-1,rev);
res.resize(n+m+1);
for(int i=0;i<=n+m;i++)
res[i]=((int)(f[i].x/k+0.5))&1;
}
void m2(vector<int>&a){
int n,m;
n=m=a.size()-1;
int k=1,ci=0;
while(k<=n+m)k<<=1,ci++;
vector<int> rev(k+1,0);
vector<cp> f(k+1);
for(int i=0;i<=n;i++)f[i].x=a[i];
for(int i=1;i<=k-1;i++)//二进制翻转
rev[i]=(rev[i>>1]>>1)|((i&1)<<(ci-1));
FFT(k,f,1,rev);
for(int i=0;i<=k;i++)
f[i]=f[i]*f[i];
FFT(k,f,-1,rev);
for(int i=0;i<=n;i++)
a[i]=((int)(f[i].x/k+0.5))&1;
}
vector<int> ksm(vector<int> a,ll p){
vector<int>ans={1};
int sz=a.size();
while(p){
if(p&1){
solve(ans,a,ans);
ans.resize(sz);
}
m2(a);
p>>=1;
}
return ans;
}
int main(){
int n;
ll k;
scanf("%d%lld",&n,&k);
n--;
int ci=1;
while(ci<n+1)ci<<=1;
k%=ci;
vector<int> a(n+1),ans(n+1);
for(int i=0;i<=n;i++){
scanf("%d",&a[i]);
}
vector<int> c(n+1);
for(int i=0;i<=n;i++)c[i]=1;
c=ksm(c,k);
for(int p=1;p<=17;p++){
vector<int> b(n+1);
for(int i=0;i<=n;i++){
b[i]=a[i]&1;
a[i]>>=1;
}
vector<int> res;
solve(b,c,res);
for(auto &x:res)x&=1;
for(int i=0;i<=n;i++){
if(res[i])
ans[i]|=(1<<(p-1));
}
}
for(int i=0;i<=n;i++){
if(i>0)printf(" ");
printf("%d",ans[i]);
}
return 0;
}