【线性基】计蒜客 The Great Nim Game

S o u c e : Souce: Souce:ACM-ICPC 2018 南京赛区网络预赛
P r o b l e m : Problem: Problem: n = 1 e 10000000 堆 石 头 ; f ( i ) = ( a f ( i − 1 ) 4 + b f ( i − 1 ) 3 + c f ( i − 1 ) 2 + d f ( i − 1 ) 1 + e − 1 ) % k + 1 , ( k ≤ 2 12 ) , 表 示 每 堆 石 头 的 大 小 。 求 多 少 个 石 头 子 集 可 以 使 得 n i m 游 戏 的 先 手 必 胜 。 n=1e10000000堆石头;f(i)=(af(i-1)^4+bf(i-1)^3+cf(i-1)^2+df(i-1)^1+e - 1)\%k+1, (k \le 2^{12}),表示每堆石头的大小。求多少个石头子集可以使得nim游戏的先手必胜。 n=1e10000000f(i)=(af(i1)4+bf(i1)3+cf(i1)2+df(i1)1+e1)%k+1,(k212)使nim
I d e a : Idea: Idea: 线 性 基 。 A n s = 2 n − 2 n − r a n k 线性基。Ans = 2^n-2^{n-rank} 线Ans=2n2nrank
C o d e : Code: Code:

#include<bits/stdc++.h>
using namespace std;
#define Toocold
#define I inline
#define lc o<<1
#define rc o<<1|1
#define fi first
#define se second
#define pb push_back
#define ALL(X) (X).begin(), (X).end()
#define bcnt(X) __builtin_popcountll(X)
#define CLR(A, X) memset(A, X, sizeof(A))
using DB = double;
using LL = long long;
using PII = pair<int, int>;
#ifdef Toocold
#define dbg(args...)\
do { cout << "DEBUG: " << #args << " -> "; err(args); } while(0)
#else
#define dbg(...)
#endif // Toocold
void err() { puts(""); }
template<template<typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args) { for(auto x:a) cout << x << ' '; err(args...); }
template<typename T, typename... Args>
void err(T a, Args... args) { cout << a << ' '; err(args...); }
/*-----------------------------------------------------------------------------*/

const int N = (1<<12)+10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
//const DB eps = 1e-8;

LL qpow(LL a, LL b) {
    b = (b+MOD-1)%(MOD-1);
    LL ret = 1;
    while(b) {
        if(b&1) ret = ret*a%MOD;
        a = a*a%MOD;
        b >>= 1;
    }
    return ret;
}

struct LinearBasis {
    int Rank;
    LL a[65];
    void init() { CLR(a, 0); Rank = 0; }
    void Insert(LL t) {
        for(int j = 60; j >= 0; j--) if(t>>j&1) {
            if(a[j]) { t ^= a[j]; continue; }
            for(int k = 0; k < j; k++) if(t>>k&1) t ^= a[k];
            for(int k = j+1; k <= 60; k++) if(a[k]>>j&1) a[k] ^= t;
            a[j] = t; Rank++;
            return;
        }
    }
}A;

const int M = 1e7+10;
char s[M];
bool vis[N];

I void work() {
    scanf("%s", s);
    int len = strlen(s), n = 0;
    int flag = 0;
    for(int i = 0; i < len; i++) {
        n = (n*10LL+s[i]-'0')%(MOD-1);
        if(n > N) flag = INF;
    }
    LL x, a, b, c, d, e, ans = qpow(2, n);
    scanf("%lld %lld%lld%lld%lld%lld", &x, &a, &b, &c, &d, &e);
    int k; scanf("%d", &k);
    if(n > k) flag = INF;
    if(flag == 0) flag = n;
    A.init();
    while(!vis[x] && flag) {
        vis[x] = 1; flag--;
        A.Insert(x);
        x = (a*x*x*x*x+b*x*x*x+c*x*x+d*x+e-1)%k+1;
    }
    (ans -= qpow(2, (n-A.Rank)%(MOD-1))) %= MOD;
    printf("%lld\n", (ans+MOD)%MOD);
}

int main() {
    work();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值