P2148 [SDOI2009]E&D
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2148 [SDOI2009]E&D相关的知识,希望对你有一定的参考价值。
题意:
有2n堆石子,第2k-1堆和第2k堆是一组,现在两个人轮流操作,每次操作任选一组石子,然后将改组中的一堆石子移走,将另一堆式子分割成两堆,形成新的两堆石子,要求每堆石子数必须大于0,谁先不能操作谁输掉游戏
题解:
我一开始先打表,利用sg的性质打表,但是没有发现啥规律,然后看了题解,题解里都是打表,不过人均一眼看出规律。。还是我太菜了
std::map<pii, int> sg;
int calc(pii c) {
if (sg.count(c)) return sg[c];
std::vector<int> s;
for(int i=1;i<=c.first-1;i++) s.push_back(calc({i, c.first - i}));
for(int i=1;i<=c.second-1;i++) s.push_back(calc({i, c.second - i}));
std::sort(s.begin(), s.end());
s.erase(std::unique(s.begin(), s.end()), s.end());
int lst = -1;
for (auto i : s) {
if (i != lst + 1) return sg[c] = lst + 1;
lst = i;
}
return sg[c] = lst + 1;
}
int main()
{
//rd_test();
pii a={50,50};
calc(a);
for(int i=1;i<=50;i++){
for(int j=1;j<=50;j++){
printf("i=%d j=%d sg=%d\\n",i,j,sg[{i,j}]);
}
}
//Time_test();
}
有人将打表结果制图得到:
选自博客
然后根据规律得到sg函数:
#define c(x, p) (x % p ? x % p : p) // 0 % p = p
int sg(ui x, ui y) {
for (ui i = 0, p = 2; i < 31; i++, p *= 2) {
if ((c(x, p) <= p / 2) && (c(y, p) <= p / 2)) return i;
}
return 31;
}
额我是没发现。。后来一艘发现这个图的样子有学名:阿达马矩阵
对于某一个矩阵H[t]递归定义为
H[1] = [1]
H[t] = [0] H[t-1]
H[t-1] H[t-1]
还有一个结论:
f(x):表示x的二进制末尾首个0的出现位置(下标从0开始),比如:f(5)=
f
(
101
)
2
f(101)_{2}
f(101)2=1
sg(x,y)为一组分别有x+1,y+1个石子的sg值
S
z
S_{z}
Sz表示满足x+y+1=z的sg(x,y)构成的自然数几集合
根据sg性质可知:
sg(x,y)=mex(
S
x
S_{x}
SxU
S
y
S_{y}
Sy)
结论:
S
z
S_{z}
Sz等同于 z 二进制下 1 的位置集合。例如
S
5
S_{5}
S5 = {0,2}
sg(x,y)=f(x|y),例如sg(1,4)=f(5)=1
证明:
具体证明
代码:
// Problem: P2148 [SDOI2009]E&D
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2148
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Data:2021-08-13 20:35:05
// By Jozky
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
template <typename T> inline void read(T& x)
{
T f= 1;
x= 0;
char ch= getchar();
while (0 == isdigit(ch)) {
if (ch == '-')
f= -1;
ch= getchar();
}
while (0 != isdigit(ch))
x= (x << 1) + (x << 3) + ch - '0', ch= getchar();
x*= f;
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime= clock();
freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
#define c(x, p) (x % p ? x % p : p) // 0 % p = p
int sg(int x, int y)
{
for (int i= 0, p= 2; i < 31; i++, p*= 2) {
if ((c(x, p) <= p / 2) && (c(y, p) <= p / 2))
return i;
}
return 31;
}
int main()
{
//rd_test();
int t;
cin >> t;
while (t--) {
ll sum= 0;
int n;
cin >> n;
for (int i= 1; i <= n; i+= 2) {
int x, y;
cin >> x >> y;
sum^= sg(x, y);
}
if (sum)
puts("YES");
else
puts("NO");
}
return 0;
//Time_test();
}
以上是关于P2148 [SDOI2009]E&D的主要内容,如果未能解决你的问题,请参考以下文章