\(K(1 \le K \le 10^9)\)堆石子,每堆石子個數不超過\(L(2 \le 50000)\),問Nim遊戲中先手必敗局面的數量,答案對\(10^9+7\)取模。c++
容易獲得\(f(i, k) = \sum_{j=0}^{n-1} f(i-1, j) f(i-1, k^j), f(1, i(2 \le i \le L))=1\),其中\(n=min(2^i, 2^i > L)\)。發現其實這就是操做爲\(xor\)的卷積。因而用鬼畜的fwt作就好了。spa
而後fwt+快速冪便可。code
// BEGIN CUT HERE // END CUT HERE #line 5 "Nim.cpp" #include <bits/stdc++.h> typedef long long ll; using namespace std; const int mo=1e9+7, N=100005, two=(1e9+8)/2; void fwt(int *a, int l, int r, int f) { if(r-l==1) { return; } int mid=(l+r)>>1; if(!f) { fwt(a, l, mid, f); fwt(a, mid, r, f); } int g=f?two:1; for(int i=l, m=(r-l)>>1; i<mid; ++i) { int x=a[i], y=a[i+m]; a[i]=(ll)(x+y)%mo*g%mo; a[i+m]=(ll)(x-y+mo)%mo*g%mo; } if(f) { fwt(a, l, mid, f); fwt(a, mid, r, f); } } int ipow(int a, int b) { int x=1; for(; b; b>>=1, a=(ll)a*a%mo) { if(b&1) { x=(ll)x*a%mo; } } return x; } int a[N]; class Nim { public: int count(int K, int L) { int len=1; for(; len<=L; len<<=1); memset(a, 0, sizeof(int)*len); for(int i=2; i<=L; ++i) { a[i]=1; } for(int i=2; i<=L; ++i) { if(a[i]) { for(int j=i+i; j<=L; j+=i) { a[j]=0; } } } fwt(a, 0, len, 0); for(int i=0; i<len; ++i) { a[i]=ipow(a[i], K); } fwt(a, 0, len, 1); return a[0]; } // BEGIN CUT HERE public: void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); } private: template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } void test_case_0() { int Arg0 = 3; int Arg1 = 7; int Arg2 = 6; verify_case(0, Arg2, count(Arg0, Arg1)); } void test_case_1() { int Arg0 = 4; int Arg1 = 13; int Arg2 = 120; verify_case(1, Arg2, count(Arg0, Arg1)); } void test_case_2() { int Arg0 = 10; int Arg1 = 100; int Arg2 = 294844622; verify_case(2, Arg2, count(Arg0, Arg1)); } void test_case_3() { int Arg0 = 123456789; int Arg1 = 12345; int Arg2 = 235511047; verify_case(3, Arg2, count(Arg0, Arg1)); } // END CUT HERE }; // BEGIN CUT HERE int main() { Nim ___test; ___test.run_test(-1); return 0; } // END CUT HERE