ACM-ICPC 2018 南京赛区网络预赛 K. The Great Nim Game(博弈)

题目链接:https://nanti.jisuanke.com/t/31000

题意:有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 }

 

posted on 2018-09-02 14:37  scau_lok  阅读(520)  评论(0编辑  收藏  举报

导航