FWT [BZOJ 4589:Hard Nim]
4589: Hard Nim
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 275 Solved: 152
[Submit][Status][Discuss]
Description
Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:
1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
由于答案可能很大,你只需要给出答案对10^9+7取模的值。
Input
输入文件包含多组数据,以EOF为结尾。
对于每组数据:
共一行两个正整数n和m。
每组数据有1<=n<=10^9, 2<=m<=50000。
不超过80组数据。
Output
Sample Input
3 7
4 13
4 13
Sample Output
6
120
120
其实这题和上午XJOI里的T3差不多。
具体做法请看别人博客http://blog.csdn.net/jr_mz/article/details/51606673
然而 问题来了。第一次我TLE了,交了Mz的代码 发现他只要6s。
然后仔细对比。。。看了好久祝天然的代码。 得出结论【啊首先 只要不开LL就不会TLE。但是时间的瓶颈不在这。】:
FWT的数组n(是2的幂、当然)只要大于(注意是严格大于。否则就WA了)其中的任意一个元素就可以。
恩。再贴一下各种FWT的公式
xor:
and:
or:
其实公式蛮好推的。。而且也不唯一 比如说 xor 还可以是 A=(A0-A1,A0+A1) 逆A就再反着算一下就可以
还有 FWT只是沿用 FFT和NTT的思想。
【FFT的思想,构造一种可逆的特殊变换trans,使得(trans(a*b))[i]=(trans(a))[i]*(trans(b))[i]。】
但是从界门纲目科属种来看 还是不像FFT与NTT 如此相似。
FWT不需要rev数组 ,举例N=8,下标为0~7。变换的时候,先对01,23,45,67做,再对02,13,46,57做,最后对04,15,26,37做。逆变换把顺序反过来就好了。
而且,这种特殊多项式乘法 满足结合律 ,trans后可以快速幂。
贴本题代码:
1 #include <bits/stdc++.h> 2 #define LL long long 3 const int mo=1000000007; 4 using namespace std; 5 int x,y,n,m,a[60005],T,t,f[140000]; 6 LL po(LL x,LL y){ 7 LL z=1; 8 for (;y;y>>=1,x=x*x%mo) 9 if (y&1) z=z*x%mo; 10 return z; 11 } 12 void fwt(int *a,int n,int d){ 13 for (m=2;m<=n;m<<=1) 14 for (int i=0,k=m>>1;i<n;i+=m) 15 for (int j=i;j<i+k;++j){ 16 int u=a[j],v=a[j+k]; 17 a[j]=(u+v)%mo,a[j+k]=(u-v)%mo; 18 } 19 if (d<0){ 20 LL x=po(n,mo-2); 21 for (int i=0;i<n;++i) a[i]=x*a[i]%mo; 22 } 23 }//注意a[i]<0 24 int main(){ 25 for (int i=2;i<=60000;++i){ 26 if (!a[i]) a[++T]=i; 27 for (int j=1;j<=T;++j){ 28 int x=a[j]*i; if (x>60000) break; 29 a[x]=1; if (!(i%a[j])) break; 30 } 31 } 32 while (scanf("%d%d",&x,&y)==2){ 33 for (t=1;a[t]<=y;++t) f[a[t]]=1; --t; 34 for (n=1;n<=a[t];n<<=1); 35 fwt(f,n,1); 36 for (int i=0;i<n;++i) f[i]=po(f[i],x); 37 fwt(f,n,-1); 38 printf("%d\n",(f[0]+mo)%mo); 39 for (int i=0;i<n;++i) f[i]=0; 40 } 41 return 0; 42 }
转载请标明出处 http://www.cnblogs.com/cyz666/