Codeforces Round #167 (Div. 1) E. Dima and Game
一个 $(l,r)$ 有两个后继,所以 sg 值最大只有 2,$r-l+1$ 相等的 pair 的 sg 值相同,那么就枚举 $d=r -l+1$,对于一个 $d$ 很容易求有多少对 $(l,r)$ 满足 $r-l+1=d$
打表发现 $d$ 的 sg 值最多只有 100 段。
设 $g_i$ 表示有多少对 $(l,r)$ sg 值为 $i$,把表打出来之后就很容易求出 $g$ 数组
那么就可以 dp 了。
$dp[i][j]$ 表示选完前 $i$ 组之后当前 sg 异或值为 $j$
$dp[i][j\oplus k]=\sum dp[i-1][j]*g[k]$,$\oplus$ 表示异或
#include <bits/stdc++.h> const int MOD = 1e9 + 7; const int N = 1007; int pos[110] = {1,3,4,5,7,9,13,15,19,27,39,40,57,58,81,85,120,121,174,179,255,260,363,382,537,544,780,805,1146,1169,1632,1718,2415,2447,3507,3622,5154,5260,7341,7730,10866,11011,15780,16298,23190,23669,33033,34784,48894,49549,71007,73340,104352,106510,148647,156527,220020,222970,319530,330029,469581,479294,668910,704371,990087,1003364,1437882,1485130,2113113,2156822,3010092,3169669,4455390,4515137,6470466,6683084,9509007,9705698,13545411,14263510,20049252,20318116,29117094,30073877,42790530,43675640,60954348,64185794,90221631,91431521,131026920,135332446,192557382,196540379,274294563,288836072,405997338,411441844,589621137,608996006,866508216,884431705,1000000001}; int sg[110] = {0,1,2,1,2,0,1,2,0,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1,2,0,2,1}; int g[3], dp[N][4], n, p; void M(int &a) { if (a >= MOD) a -= MOD; if (a < 0) a += MOD; } int cal(int l, int r) { l = p - l, r = p - r; return 1LL * (l + r) * (l - r + 1) / 2 % MOD; } int main() { scanf("%d%d", &n, &p); for (int i = 0; i < 102; i++) { if (pos[i] > p) break; int l = pos[i], r = std::min(pos[i + 1] - 1, p); M(g[sg[i]] += cal(l, r)); } dp[0][0] = 1; for (int i = 1; i <= n; i++) { for (int j = 0; j < 4; j++) { for (int k = 0; k <= 2; k++) { M(dp[i][j ^ k] += 1LL * dp[i - 1][j] * g[k] % MOD); } } } int ans = 0; for (int i = 1; i < 4; i++) M(ans += dp[n][i]); printf("%d\n", ans); return 0; }