\2022河南萌新联赛第(一)场:河南工业大学\Alice_and_Bob
//题意:Alice 和 Bob 正在玩一个游戏,双方都很聪明。游戏是这样的,给出一个正整数 n,然后每次轮流操作,
//每次操作需要将数 n 除以 a^k。Alice 先手,谁先将数 n变为 1 则谁输。(a必须为质数,且a^k能够整除n,a,k为正整数)
//anti Nim
//有n堆石子(n>0),每一堆有ai个石子每人每次可以从任意一堆石子里,取出任意多枚石子扔掉,
//可以取完,不能不取,每次只能从一堆里取。最后没有石子可以取的人输掉这场游戏。
//思路:将n分解成质因数,每个质因数为一堆石子的一个,转化成anti nim博弈
//先手必胜的条件为
// 所有堆的石子数均 = 1 ,且有偶数堆,这个偶数堆在这个情况下其实就是异或和为0 。
// 至少有一个堆的石子数 > 1,且石子堆的异或和 ≠ 0。
#include
#include
#include
#include
sg函数
1.可选步数为1~m的连续数sg(x)=x%(m+1)
2.可选步数为任意个数sg(x)=x
3.可选不连续个数:打表
f[]:可以取走的石子个数
sg[]:0~n的SG函数值
hash[]:mex{}
int f[N], sg[N], hash[N];
void getSG(int n)
{
int i, j;
memset(sg, 0, sizeof(sg));
for (i = 1; i <= n; i++){
memset(hash, 0, sizeof(hash));
for (j = 1; f[j] <= i; j++)
hash[sg[i - f[j]]] = 1;
for (j = 0; j <= n; j++){ //求mes{}中未出现的最小的非负整数
if (hash[j] == 0){
sg[i] = j;
break;
}
}
}
}
经典博弈总结
anti Nim
有n堆石子(n>0),每一堆有ai个石子每人每次可以从任意一堆石子里,取出任意多枚石子扔掉,
可以取完,不能不取,每次只能从一堆里取。最后没有石子可以取的人输掉这场游戏。
先手必胜的条件为
所有堆的石子数均 = 1 ,且有偶数堆,这个偶数堆在这个情况下其实就是异或和为0 。
至少有一个堆的石子数 > 1,且石子堆的异或和 ≠ 0。
斐波那契博弈(Fibonacci Nim)
有n张纸牌,A,B两人轮流按照以下规则取牌。
A先取,但是不能在第一次将纸牌全部取完,而且至少要取一张;
每次所取纸牌张数必须大于或等于1, 且小于等于对手刚取的纸牌张数的两倍。取到最后一张牌者为胜者。
结论:⑴如果牌的张数n是Fibonacci数时,先取牌者必败。
⑵对所有非Fibonacci数都是先取人必赢,反之,必败。
stairacse nim
有n堆石头,每次可以从一堆中拿出一些或全部石头给相邻的右边的一堆石头,
或者最后一堆减去一些或全部石头,谁不能操作谁输,
假设从最后一堆石头开始与上一堆相间的石头数的异或和为P,P为0时先手必败反之必胜。
比如a1,a2,a3,a4,a5 P的值就是a5 ^ a3 ^ a1
wythoff game
有两堆各若干个物品,两个人轮流从任一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,
多者不限,最后取光者得胜。
公式
#include
using namespace std;
int a, b;
int main() {
while (cin >> a >> b) {
int sum = a + b;
a = min(a, b);
b = sum - a;
if ((int)(double(b - a) * (sqrt(5) + 1) / 2) == a) cout <<"先手输" << endl;
else cout << "先手胜" << endl;
}
return 0;
}
bash博弈
只有一堆n个物品, 两个人轮流从这堆物品中取物, 规定每次至少取一个, 最多取m个.
最后取光着胜
n%(m + 1) = 0,先手输。反之先手必胜。
最后取光者输
当n = (m + 1) × k + 1时,先手输,否则先手必胜。
二维数点
步骤总结
1.将查询分为四个,2.离散化,3.按x轴排序,4遇见操作操作,遇见查询查询
5.将查询的以二维前缀和的方式算出
解决:给出一个二维平面內的若干个点,多次询问某个矩形区域內包含多少个点(边界也算)。
又或者,给一个长为n的序列,多次询问[l.r]内有多少值在[x,y]的元素的个数
P2163 [SHOI2007] 园丁的烦恼
给定n个坐标,q次询问,每次询问给定一个矩形,求在矩形里的点
#include
#include
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
typedef long long ll;
typedef pair pii;
inline int IntRead() { char ch = getchar(); int s = 0, w = 1; while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }return s * w; }
#define y1 y114514
#define MAX 2000000 + 50
int n, m, k, op;
int x1, x2, y1, y2;
struct ran {
int x, y;
}tr[MAX];
bool cmp(ran a, ran b) {
if (a.x != b.x)return a.x < b.x;
else return a.y < b.y;
}
int tot;
struct ranran {
int x, y, id;
}ar[MAX];
bool cmpp(ranran a, ranran b) {
if (a.x != b.x)return a.x < b.x;
else return a.y < b.y;
}
int sum[MAX];
inline int lowbit(int x) {
return x & (-x);
}
inline int getans(int x) {
int ans = 0;
for(int i=x;i;i-=i&-i){
ans += sum[i];
}
return ans;
}
inline void insert(int x, int c) {
for (int i = x; i <= n + 2 * m;i+=i&-i) {
sum[i] += c;
}
}
int ans[MAX];
int main() {
n = IntRead(); m = IntRead();
vectorv;
for (int i = 1; i <= n; ++i) {
tr[i].x = IntRead(); tr[i].y = IntRead();
v.push_back(tr[i].y);
}
for (int i = 1; i <= m; ++i) {
x1 = IntRead(); y1 = IntRead();
x2 = IntRead(); y2 = IntRead();
v.push_back(y2); v.push_back(y1 - 1);
++tot; ar[tot].id = tot; ar[tot].x = x2; ar[tot].y = y2;
++tot; ar[tot].id = tot; ar[tot].x = x2; ar[tot].y = y1 - 1;
++tot; ar[tot].id = tot; ar[tot].x = x1 - 1; ar[tot].y = y2;
++tot; ar[tot].id = tot; ar[tot].x = x1 - 1; ar[tot].y = y1 - 1;
}
sort(tr + 1, tr + 1 + n, cmp); //按x
sort(ar + 1, ar + 1 + tot, cmpp);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
int cnt = 1;
for (int i = 1; i <= tot; ++i) {
while (cnt <= n && tr[cnt].x <= ar[i].x) { //先操作
int p = (int)(lower_bound(v.begin(), v.end(), tr[cnt].y) - v.begin());
insert(p + 1, 1);
++cnt;
}
int p = (int)(lower_bound(v.begin(), v.end(), ar[i].y) - v.begin()); //查询
ans[ar[i].id] += getans(p + 1);
}
for (int i = 1; i <= tot; i += 4) {
printf("%d\n", ans[i] + ans[i + 3] - ans[i + 1] - ans[i + 2]);
}
return 0;
}