题解 P5387 【[Cnoi2019]人形演舞】
EternalAlexander · · 题解
怎么没有题解,水一个。
考虑怎么算
假设上述结论对所有
若
对于
否则,设去掉最高位的
综上,
至此我们可以在
设
那么现在的问题就是怎么做异或卷积快速幂,每次 FWT 一遍复杂度不太对,我们可以先 FWT 一次,然后用 FWT 后的数组做乘法,最后 FWT 回来,就可以做到
至此我们在
#include <bits/stdc++.h>
#define maxn 1048576
#define ll long long
const int mod=998244353;
const int inv2=(mod+1)/2;
int A[maxn],b[maxn],n,lim;
ll k;
int SG(int x){
int len=1,sum=0;
while(sum<x){
sum+=len;
if(sum>=x)return x-(sum-len);
len<<=1;
}
}
void FWT(int *a,int lim,int flag){
for(int i=1;i<lim;i<<=1)
for(int j=0;j<lim;j+=(i<<1))
for(int k=0;k<i;++k){
int a1=a[j+k],a2=a[j+k+i];
a[j+k]=(a1+a2)%mod;a[j+k+i]=(a1-a2+mod)%mod;
if(flag==-1){
a[j+k]=(ll)a[j+k]*inv2%mod;a[j+k+i]=(ll)a[j+k+i]*inv2%mod;
}
}
}
void mul(int *a,int *b,int lim){
for(int i=0;i<lim;++i)a[i]=(ll)a[i]*b[i]%mod;
}
void qpow(int *a,ll k,int lim){
b[0]=1;FWT(b,lim,1);
while(k){
if(k&1)mul(b,a,lim);
mul(a,a,lim);
k>>=1;
}std::memcpy(a,b,sizeof(b));
}
int main(){
int max=0;lim=1;
scanf("%lld%d",&k,&n);
for(int i=1;i<=n;++i){
int d=SG(i);
A[d]++;
max=std::max(max,d);
}while(lim<=max)lim<<=1;
FWT(A,lim,1);
qpow(A,k,lim);
FWT(A,lim,-1);
int sum=0;
for(int i=1;i<lim;++i)sum=(sum+A[i])%mod;
printf("%d",sum);
return 0;
}