(南京区域资格赛)K - The Great Nim Game(博弈)

Nim is a famous game as you know. Nim is a 222-player game featuring several piles of stones. Players alternate turns, and on his/her turn, a player’s move consists of removing one or more stones from any single pile. Play ends when all the stones have been removed. The first player who can’t remove is declared as the loser.

Now you want to play the Great Nim Game. In the other words, you want to choose several (0(0(0 ~ N)N)N) pile(s) from NNN piles of stones. You want know how many choices you have making sure that the first player must win. They both try their best (optimal strategy) to win through the game.
Input

The first line contains two numbers N x1N\ x_1N x1​, denoting the number of piles and the number of stones in the first pile.

The second line contains five integers a,b,c,d,ea, b, c, d, ea,b,c,d,e.

The third line contains one integer kkk, denoting a function

f(x)=f(x)=f(x)=
(ax4+bx3+cx2+dx1+e−1)%k+1(ax^4+bx^3+cx^2+dx^1+e - 1)\%k+1(ax4+bx3+cx2+dx1+e−1)%k+1.

With these, you can figure out the number of stones in the iii-th pile xi=f(xi−1)(1

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int MAXN = 1e7 + 10;
const int MAXM = 2e6 + 10;
const ll mod = 1e9 + 7;

bool vis[4105];
int dp[2][8192];
vector<int>vec;
int f[4105];

ll pow_mod(ll a, ll n) {
    ll ans = 1;
    while(n) {
        if(n & 1) ans = ans * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans;
}

int main() {
    ll ans = 0;
    char ch;
    int len = 0;
    int n = 1e9;
    while(1) {
        scanf("%c", &ch);
        if(ch == ' ') break;
        ans = pow_mod(ans, 10);
        if(len == 0) ans = 1;
        ans = ans * (1ll << (ch - '0')) % mod;
        if(len <= 5) {
            if(len == 0)
                n = 0;
            n = n * 10 + ch - '0';
            len++;
        }
    }
    int x;
    scanf("%d", &x);
    int temp = x;
    int a, b, c, d, e, k;
    scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &e, &k);
    vec.push_back(x);
    vis[x] = true;
    for(int i = 1; i <= 4100; i++) {
        int x1 = 1ll * a * i * i % k * i * i % k;
        int x2 = 1ll * b * i * i % k * i % k;
        int x3 = 1ll * c * i * i % k;
        int x4 = 1ll * d * i;
        x = (x1 + x2 + x3 + x4 + e - 1) % k + 1;
        f[i] = x;
    }
    int all = 0;
    while(all < n) {
        all++;
        int now = f[temp];
        if(!vis[now]) {
            vis[now] = true;
            vec.push_back(now);
            temp = now;
        } else break;
    }
    int sz = vec.size();
    dp[0][0] = 1;
    int pre = 1, now = 0;
    for(int i = 1; i <= sz; i++) {
        swap(pre, now);
        int num = vec[i - 1];
        for(int j = 0; j < 8192; j++) dp[now][j] = dp[pre][j];
        for(int j = 0; j < 8192; j++) {
            dp[now][j ^ num] += dp[pre][j];
            if(dp[now][j ^ num] >= mod) dp[now][j ^ num] -= mod;
        }
    }
    ll sum = 0;
    for(int i = 1; i < 8192; i++) {
        sum += dp[now][i];
        if(sum >= mod) sum -= mod;
    }
    ll inv = pow_mod(2, sz);
    inv = pow_mod(inv, mod - 2);
    ans = ans * inv % mod;
    ans = ans * sum % mod;
    printf("%lld\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值