当前位置:网站首页>2020CCPC威海 J - Steins;Game (sg函数、线性基)
2020CCPC威海 J - Steins;Game (sg函数、线性基)
2022-07-07 07:09:00 【moyangxian】
题意:n堆石子,每堆石子有黑和白两种颜色,拿黑色堆石子的时候必须拿数量最少的(最少一个),白色没有限制可以任意拿(最少一个)。后手的人可以在游戏开始之前对所有石子堆染色,问后手能赢的染色方案数。
题解:首先可以将黑色和白色分成两个游戏,两个游戏的异或和为0即后手胜利。
白色游戏:相当于nim游戏
黑色游戏:通过sg打表能发现
SG值 = 最小堆石子数 − ( ( 最小堆数量 + [ 所有堆石子数相同 ] ) % 2 )
能发现sg值只跟最小堆有关系,然后我们可以枚举最小堆。用一个pre维护异或前缀和,suf维护异或后缀和,从后往前维护一个线性基。由于我们枚举到的堆是最小堆,所以石子数量比当前枚举的堆要少的一定是白色,我们要最后总的异或值为0,那么要看线性基里能不能表示出满足异或和为0的数,方案即 2的(s - tot)次方。最后再乘上一个组合数即可。具体细节代码可见。
sg函数打表代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int sg[N];
int SG(priority_queue<int, vector<int>, greater<int> > q) {
bool vis[N] = {
false };
if (q.empty()) return 0;
int t = q.top();
q.pop();
vis[SG(q)] = true;
for (int i = 1; i < t; i++) {
auto tmp = q;
tmp.push(t - i);
vis[SG(tmp)] = true;
}
for (int i = 0; ; i++)
if (!vis[i]) return i;
}
int main() {
priority_queue<int, vector<int>, greater<int> > q;
for (int i = 0; i <= 5; i++) {
for (int j = i; j <= 5; j++) {
for (int k = j; k <= 5; k++) {
for (int l = k; l <= 5; l++) {
for (int r = l; r <= 5; r++) {
while (!q.empty()) q.pop();
if (i) q.push(i), cout << i << " ";
if (j) q.push(j), cout << j << " ";
if (k) q.push(k), cout << k << " ";
if (l) q.push(l), cout << l << " ";
if (r) q.push(r), cout << r << " ";
cout << " : " << SG(q) << endl;
}
}
}
}
}
return 0;
}
题目代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int f[N], inv[N];
int a[N], pre[N], suf[N];
int same[N], num[N];
map<int, int> t;
struct LB {
const static int N = 64;
ll a[N + 1], tot;
LB() {
memset(a, 0, sizeof(a)), tot = 0; }
bool insert(ll x) {
for (int i = N; i >= 0; i--) {
if (x & (1ll << i)) {
if (a[i]) x ^= a[i];
else {
a[i] = x;
tot++;
break;
}
}
}
return x > 0;
}
bool count(ll x) {
for (int i = N; i >= 0; i--)
if (x & (1ll << i)) x ^= a[i];
return x == 0;
}
}LB;
int qpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void init(int n) {
f[0] = inv[0] = 1;
for (int i = 1; i <= n; i++)
f[i] = f[i - 1] * i % mod;
inv[n] = qpow(f[n], mod - 2);
for (int i = n - 1; i >= 1; i--)
inv[i] = inv[i + 1] * (i + 1) % mod;
}
int C(int a, int b) {
if (a < b) return 0;
return f[a] * inv[b] % mod * inv[a - b] % mod;
}
signed main() {
init(N - 1);
int n;
cin >> n;
int ans = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
t[a[i]]++;
ans ^= a[i];
}
ans = (ans == 0 ? 1 : 0);
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] ^ a[i];
for (int i = n; i >= 1; i--)
suf[i] = suf[i + 1] ^ a[i];
for (int i = n; i >= 1; i--) {
same[i] = (a[i] == a[i + 1] ? same[i + 1] + 1 : 1);
num[i] = t[a[i]];
}
int head = n + 1;
for (int i = n; i >= 1; i--) {
int sum = 0;//记录方案
int x = pre[i - 1];//前缀异或和
int y = a[i] - ((same[i] + 1) & 1);
//当前选了same[i]个数量为a[i]的石堆染成黑色(所有石堆石子数相同)
int z = suf[i + same[i]];//后缀异或和
if ((x ^ y ^ z) == 0) sum = (sum + 1) % mod;//如果异或和为0,方法数加一
y = a[i] - (same[i] & 1);//同上y,但是所有石堆石子数不相同
int need = x ^ y;//满足异或和为0的数
if (LB.count(need)) sum = (sum + qpow(2, n - head + 1 - LB.tot)) % mod;
//如果need能用线性基表示出来,线性基能表示出这个数的方案为2^(s - tot)
//s为线性基插入次数,tot为线性基内的个数
if ((need ^ suf[i + same[i]]) == 0) sum = (sum - 1 + mod) % mod;
//如果后缀所有数异或和等于need那么方案数要减一
if (same[i - 1] == 1) {
//如果当前是a[i]数量的最后一个石堆,把所有值为a[i]的数插入到线性基中
for (int j = 1; j <= same[i]; j++) LB.insert(a[i]);
head = i;
}
ans = (ans + sum * C(num[i], same[i]) % mod) % mod;
//最后要乘上在num[i]中选same[i]堆的方法数
}
cout << ans << endl;
return 0;
}
边栏推荐
- 第一讲:寻找矩阵的极小值
- Unity shader (pass user data to shader)
- Write VBA in Excel, connect to Oracle and query the contents in the database
- Loxodonframework quick start
- shake数据库中怎么使用Mongo-shake实现MongoDB的双向同步啊?
- 创建一个长度为6的int型数组,要求数组元素的值都在1-30之间,且是随机赋值。同时,要求元素的值各不相同。
- [4G/5G/6G专题基础-147]: 6G总体愿景与潜在关键技术白皮书解读-2-6G发展的宏观驱动力
- JS逆向教程第一发
- Information Security Experiment 1: implementation of DES encryption algorithm
- 浏览器中如何让视频倍速播放
猜你喜欢
随机推荐
esp8266使用TF卡并读写数据(基于arduino)
STM32 and motor development (from stand-alone version to Networking)
Over 100000 words_ Ultra detailed SSM integration practice_ Manually implement permission management
JS judge whether checkbox is selected in the project
Binary tree high frequency question type
Esp8266 uses TF card and reads and writes data (based on Arduino)
ComputeShader
Sqlplus garbled code problem, find the solution
Yapi test plug-in -- cross request
战略合作|SubQuery 成为章鱼网络浏览器的秘密武器
Redis common commands
Netease Cloud Wechat applet
Kubernetes cluster capacity expansion to add node nodes
4、 Fundamentals of machine learning
sql 里面使用中文字符判断有问题,哪位遇到过?比如value&lt;&gt;`无`
印象笔记终于支持默认markdown预览模式
牛客网——华为题库(61~70)
Information Security Experiment 4: implementation of IP packet monitoring program
面试被问到了解哪些开发模型?看这一篇就够了
Nested (multi-level) childrn routes, query parameters, named routes, replace attribute, props configuration of routes, params parameters of routes