P2148 [SDOI2009]E&D

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2148 [SDOI2009]E&D相关的知识,希望对你有一定的参考价值。

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的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2148 [SDOI2009]E&D

[luogu] P2148 [SDOI2009]E&D

SDOI2009 E&D

Bzoj1228 [SDOI2009]E&D

BZOJ1228: [SDOI2009]E&D

[SDOI2009]E&D