0%

[ARC151C] 01 Game

这场做完B就去写作业了...

题目当时瞅了一眼,感觉不算特别难。

题目链接。

题意

现在有 个格子,编号为 。对于每一个 ,格子 与格子 是相邻的。

最初,有 个方格上写有数字,第 个方格上写的数字是 ,每一个格子上面的数字只能是 或 。剩下的 个方格上没有数字。

现在,高桥和青木将轮流执行一下操作,高桥先执行。

选择一个上面没有数字的方格,在上面写下 或 ,需要保证这个方格与它相邻的方格,上面的数字不同。

如果一个人不能操作,游戏结束,那个不能操作的人就输了。

如果两个人都按最优方案进行操作,谁会赢?

。

。

。

。

。

题解

首先我们知道,这题是个博弈论(废话

我们会发现,假如有两段空白的区域,中间用若干个数字隔开,那么这两段在操作的时候是不会互相影响的。

并且两个人可执行的操作是完全相同的。

所以我们知道,这道题是一个公平博弈,而且使用SG函数大概率可以做出来。

不过这道题的SG函数比较复杂,因为需要多种情况进行讨论。

我们设 为一段长度为 的两端数字相等的空白区域的SG函数值。

设 为一段长度为 的两端数字不等的空白区域的SG函数值。

设 为一段长度为 的一端为格子边界( 或 )的空白区域的SG函数值。

设 为一段长度为 的两端都为格子边界的空白区域的SG函数值。

看起来很不好求,所以我们进行打表。

打出来的结果放在这里:

打表程序

会发现SG函数的特征还是比较明显的。

做到这里其实就可以直接使用 SG 函数解决了,时间复杂度是 的。

不过这个结论终究是打表看出来的,下面来证明一下:

证明

我们现在需要证明的是对于任何正整数 ,都有 。

是用数学归纳法。

首先对于 ,结论显然成立。

现在假设,对于一个 ,所有 都满足结论,现在证明对于 ,也满足结论。


对于 :

显然,一共有两种情况:

  1. 分成两段长度 的两端相同的空白段,此时可达到的 值为 。
  2. 分成两段长度 的两端不同的空白段,此时可达到的 值为 。

所以 。


对于 :

显然,一共有一种情况。

分成一段长度 的两端相同的空白段和一段长度 的两端不同的空白段。

可以达到的 值为 。

所以 。


对于 :

显然,一共有两种情况。

  1. 分成一段长度 的两端相同的空白段和一段长度 的一端为边界的空白段,设含边界的一段长度为 。

    则此时可以到达的 值为 ,并且可以知道:。

  2. 分成一段长度 的两端不同的空白段和一段长度 的一端为边界的空白段,设含边界的一段长度为 。

    则此时可以到达的 为 ,并且可以知道,可以到达的所有 恰好为 的所有整数。

所以 。


对于 :

显然,一共有一种情况。

分成两端长度 的一端为边界的空白段,假设其中一段的长度为 ,则另一段的长度为 。

  1. 当 为偶数时, 与 恰好有一个是偶数,一个是奇数。

    此时

  2. 当 为奇数时, 与 奇偶性相同。

    取 时,,到达的 值为 。

    因为他们两个奇偶性相同,所以到达的 值不可能为奇数。

    此时 。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
using ll=long long;
using pli=pair<ll,int>;
using pi=pair<int,int>;
template<typename A>
using vc=vector<A>;
inline int read()
{
int s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline ll lread()
{
ll s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
ll ans;
int m;
ll n;
ll get(int lst,int now,ll len)
{
if(len==0) return 0;
if(lst==-1||now==-1)
{
if(lst==-1&&now==-1) return len&1;
if(len==1) return 1;
return len;
}
return lst==now;
}
int main()
{
n=lread(),m=read();
ll lst=0;int type=-1;
for(int i=1;i<=m;i++)
{
ll now=lread();int ty=read();
ans^=get(type,ty,now-lst-1);
lst=now,type=ty;
}
ans^=get(type,-1,n-lst);
if(ans) printf("Takahashi\n");
else printf("Aoki\n");
return 0;
}

感谢观看!