[bzoj4589]Hard Nim【FWT】
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=4589
【题解】
就是求堆石子异或和为的方案数。
这个东西显然满足结合律,因此倍增计算就行了。暴力的复杂度。
考虑用FWT优化转移,这是经典的xor卷积。
复杂度。
/* --------------
user Vanisher
problem bzoj-4589
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define M 100010
# define N 100010
# define P 1000000007
using namespace std;
ll read(){
ll tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
ll mypow(ll x, ll y){
ll i=x; x=1;
while (y>0){
if (y%2==1) x=x*i%P;
i=i*i%P;
y/=2;
}
return x;
}
ll rev=mypow(2,P-2),j[N],f[M+10],p[M+10],pnum,n,m,a[N],l;
void FWT(ll *a, ll l){
for(ll d=1; d<l; d<<=1)
for(ll m=(d<<1),i=0; i<l; i+=m)
for(ll j=0;j<d;j++)
{
ll x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)%P,a[i+j+d]=(x-y+P)%P;
}
}
void UFWT(ll *a, ll l){
for(ll d=1; d<l; d<<=1)
for(ll m=(d<<1),i=0; i<l; i+=m)
for(ll j=0;j<d;j++)
{
ll x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)*rev%P,a[i+j+d]=((x-y)*rev%P+P)%P;
}
}
void mypow(ll *x, ll y, ll l){
for (ll i=0; i<l; i++) j[i]=x[i];
for (ll i=0; i<l; i++) x[i]=1;
while (y>0){
if (y%2==1) for (ll i=0; i<l; i++) x[i]=(x[i]*j[i])%P;
for (ll i=0; i<l; i++) j[i]=(j[i]*j[i])%P;
y/=2;
}
}
void getp(){
f[1]=true;
for (ll i=2; i<=M; i++)
if (f[i]==false){
p[++pnum]=i;
for (ll j=i+i; j<=M; j+=i)
f[j]=true;
}
}
int main(){
getp();
while (scanf("%lld%lld",&n,&m)!=EOF){
memset(a,0,sizeof(a));
for (ll i=1; p[i]<=m; i++) a[p[i]]=1;
l=1; while (l<=m) l<<=1;
FWT(a,l);
mypow(a,n,l);
UFWT(a,l);
printf("%lld\n",a[0]);
}
return 0;
}