[数学记录]P5387 [Cnoi2019]人形演舞
command_block · · 个人记录
题意 : 对一堆大小为
选定
现在有
两人轮流操作,不能操作者负。问先手必胜的情况数。
答案对
若
若
考虑归纳证明 : 对于
对于
对于
则后继
所以
容易求出
现在问题变成了 : 在集合
使用异或卷积快速幂即可。
复杂度
#include<algorithm>
#include<cstdio>
#define ll long long
#define MaxN 1050000
using namespace std;
const int mod=998244353;
ll powM(ll a,int t=mod-2){
ll ret=1;
while(t){
if (t&1)ret=ret*a%mod;
a=a*a%mod;t>>=1;
}return ret;
}
void FWT(ll *F,int n)
{
for (int len=1;len<n;len<<=1)
for (int p=0;p<n;p+=len+len)
for (int k=0;k<len;k++){
ll sav0=F[p|k];
F[p|k]=sav0+F[p|len|k];
F[p|len|k]=sav0-F[p|len|k];
}
for (int i=0;i<n;i++)F[i]%=mod;
}
int n,m,h[MaxN];
ll k,F[MaxN];
int main()
{
scanf("%lld%d",&k,&m);
k%=(mod-1);
for (n=1;n<=m;n<<=1);
for (int i=1;i<=m;i++){
h[i]=max(h[i>>1]<<1,i&1);
F[(i^h[i])+1]++;
}
FWT(F,n);
for (int i=0;i<n;i++)
F[i]=powM(F[i],k);
FWT(F,n);
ll ans=(powM(m,k)-powM(n)*F[0])%mod;
printf("%lld",(ans+mod)%mod);
return 0;
}