题意:有N堆石子(N为大数),每堆的个数按一定方式生成,问先手取若干堆进行尼姆博弈,必胜的方式有多少种。
题解:因为 k < 4096,所以出现的数最多只有4096个,对每个数字只考虑出现奇/偶次进行dp,答案是所有不等于0的dp值的和。然后如果一个数字出现x次,它对自己出现奇数次的方案数和偶数次的方案数贡献都是乘上2 ^ (x - 1),每个数字的贡献都是2 ^ (x - 1) 总贡献就是2 ^ (N - ∑(vis[i]))。大数可以一边读入一边取模。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define fi first 8 #define se second 9 #define pi acos(-1) 10 #define pii pair<int,int> 11 const int INF = 0x3f3f3f3f; 12 const double eps = 1e-6; 13 const int MAXN = 1e7 + 10; 14 const int MAXM = 2e6 + 10; 15 const ll mod = 1e9 + 7; 16 17 bool vis[4105]; 18 int dp[2][8192]; 19 vector<int>vec; 20 int f[4105]; 21 22 ll pow_mod(ll a, ll n) { 23 ll ans = 1; 24 while(n) { 25 if(n & 1) ans = ans * a % mod; 26 a = a * a % mod; 27 n >>= 1; 28 } 29 return ans; 30 } 31 32 int main() { 33 #ifdef local 34 freopen("data.txt", "r", stdin); 35 // freopen("data.txt", "w", stdout); 36 #endif 37 ll ans = 0; 38 char ch; 39 int len = 0; 40 int n = 1e9; 41 while(1) { 42 scanf("%c", &ch); 43 if(ch == ‘ ‘) break; 44 ans = pow_mod(ans, 10); 45 if(len == 0) ans = 1; 46 ans = ans * (1ll << (ch - ‘0‘)) % mod; 47 if(len <= 5) { 48 if(len == 0) 49 n = 0; 50 n = n * 10 + ch - ‘0‘; 51 len++; 52 } 53 } 54 int x; 55 scanf("%d", &x); 56 int temp = x; 57 int a, b, c, d, e, k; 58 scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &e, &k); 59 vec.push_back(x); 60 vis[x] = true; 61 for(int i = 1; i <= 4100; i++) { 62 int x1 = 1ll * a * i * i % k * i * i % k; 63 int x2 = 1ll * b * i * i % k * i % k; 64 int x3 = 1ll * c * i * i % k; 65 int x4 = 1ll * d * i; 66 x = (x1 + x2 + x3 + x4 + e - 1) % k + 1; 67 f[i] = x; 68 } 69 int all = 0; 70 while(all < n) { 71 all++; 72 int now = f[temp]; 73 if(!vis[now]) { 74 vis[now] = true; 75 vec.push_back(now); 76 temp = now; 77 } else break; 78 } 79 int sz = vec.size(); 80 dp[0][0] = 1; 81 int pre = 1, now = 0; 82 for(int i = 1; i <= sz; i++) { 83 swap(pre, now); 84 int num = vec[i - 1]; 85 for(int j = 0; j < 8192; j++) dp[now][j] = dp[pre][j]; 86 for(int j = 0; j < 8192; j++) { 87 dp[now][j ^ num] += dp[pre][j]; 88 if(dp[now][j ^ num] >= mod) dp[now][j ^ num] -= mod; 89 } 90 } 91 ll sum = 0; 92 for(int i = 1; i < 8192; i++) { 93 sum += dp[now][i]; 94 if(sum >= mod) sum -= mod; 95 } 96 ll inv = pow_mod(2, sz); 97 inv = pow_mod(inv, mod - 2); 98 ans = ans * inv % mod; 99 ans = ans * sum % mod; 100 printf("%lld\n", ans); 101 return 0; 102 }
原文地址:https://www.cnblogs.com/scaulok/p/9573791.html
时间: 2024-11-06 07:10:52