博弈论练习1

博弈论练习1

   \;

1.ProjectEuler306 Paper-strip Game

题目描述

Solution

S G [ i ] SG[i] 表示连续 i i 个格子的 S G SG 值。
S G [ 0 ] = S G [ 1 ] = 0 S G [ i ] = m e x j = 0 n 2 { S G [ j ]      x o r      S G [ i j 2 ] } SG[0]=SG[1]=0 \\ SG[i]=mex_{j=0}^{n-2}\{SG[j]\;\;xor\;\;SG[i-j-2]\}
直接暴力时间复杂度 O ( n 2 ) O(n^2)
打表找规律,发现有34位的循环节,之后 O ( n ) O(n) 求解答案即可。

   \;

2.AGC002E-Candy Piles

题目描述

Solution

本题有两种操作:
1.整体减1。
2.删除最大的数。

我们把数从大到小排序,按数的大小柱形图,相当于每次可以删掉底行或删掉首列, f [ i ] [ j ] f[i][j] 表示已经删除前 i i 行前 j j 列的胜负状态,发现每一个对角线的 f f 值都是相同的。

因此直接从起点走到轮廓线判断奇偶性即可。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

using namespace std;

template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;

const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
int a[MAXN];
int main()
{
	int n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	sort(a+1,a+n+1,greater<int>());
	for (int i=0;i<=n;i++)
		if (i+1>a[i+1])
		{
			int r=i;
			while (a[r+1]==i) r++;
			puts((((a[i]-i)&1)||((r-i)&1))?"First":"Second");
			break;
		}
	return 0;
}

3.CF1110G. Tree-Tac-Toe

题目描述

Solution

首先,后手是个弟弟,他永远不能赢 Q A Q QAQ
因此考虑什么时候先手必胜:
1.若有一个度数为4及以上的结点,则先手必胜。
2.若有一个度数为3的结点,它的子节点的度数至少为1,2,2,则先手必胜。
3.若有存在3个以上度数为3的结点,必然存在条件2,则先手必胜。
4.若仅有2个度数为3的结点,则若他们之间的距离是偶数,则先手必胜。

否则必然平局。
O ( n ) O(n) 实现分类讨论即可。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
 
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
 
using namespace std;
 
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
 
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
 
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=2000005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
char st[MAXN];
int n,nodenum,d[MAXN];
vector<int> e[MAXN],V[MAXN];
void add_edge(int u,int v)
{
	e[u].PB(v),e[v].PB(u);
	d[u]++,d[v]++;
}
int dfs(int x,int father,int dep,int y)
{
	if (x==y) return dep&1; 
	for (auto v:e[x])
	{
		if (v==father) continue;
		int q=dfs(v,x,dep+1,y);
		if (q!=-1) return q;
	}
	return -1;
}
bool solve()
{
	for (int i=1;i<=nodenum;i++) 
	{
		if (d[i]>=4) return 1;
		V[d[i]].PB(i);
	}
	if (V[3].size()>=3) return 1;
	if (V[3].size()==2&&dfs(V[3][0],0,1,V[3][1])) return 1;
	
	for (auto x:V[3])
	{	
		int cnt1=0,cnt2=0;
		for (auto v:e[x]) if (d[v]>=2) cnt2++;
		if (cnt2>=2) return 1;
	}
	return 0;
}
int main()
{
	int Case=read();
	while (Case--)
	{
		n=nodenum=read();
		for (int i=1;i<n;i++)
		{
			int u=read(),v=read();
			add_edge(u,v);
		}
		scanf("%s",st+1);
		for (int i=1;i<=n;i++)
			if (st[i]=='W')
			{
				nodenum+=3;
				add_edge(i,nodenum-2);
				add_edge(nodenum-2,nodenum-1);
				add_edge(nodenum-2,nodenum);
			}
		puts(solve()?"White":"Draw");
		for (int i=1;i<=nodenum;i++) e[i].clear(),V[i].clear(),d[i]=0;
	}
	return 0;
}

4.CF388C. Fox and Card Game

题目描述

Solution

这题虽然是 D i v . 1 C Div.1C 但是很简单啊。

这个博弈游戏中,先手想要拿到最大的权值和,而后手的目的是尽可能地阻止先手拿到大的权值。

考虑每一行的数,倘若先手拿到 a [ ( n + 1 ) / 2 + 1... n ] a[(n+1)/2+1...n] 中的某一个数能拿到最优解,那么先手必然会阻止他拿到他想拿到的那个数,换句话说,在后手刻意而为的情况下,先手永远拿不到每一行中的 a [ ( n + 1 ) / 2 + 1... n ] a[(n+1)/2+1...n] 这些数。

对于 n n 为偶数,先手能拿的只有前 n / 2 n/2 个。
对于 n n 为奇数,先手必然能拿的是前 n / 2 n/2 ,并剩下最中间一个数。对于每一个奇数行剩下的数从大到小排序,先手必然可以选到排序后奇数位上的数,剩下的数全部由后手选到。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
 
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
 
using namespace std;
 
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
 
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
 
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
vector<int> V;
int main()
{
	int n=read(),ans1=0,ans2=0;
	for (int i=1;i<=n;i++)
	{
		int x=read();
		for (int j=1;j<=x;j++)
			if (j<=x/2) ans1+=read();
			else if (j==(x+1)/2) V.PB(read());
			else ans2+=read();
	}
	sort(V.begin(),V.end(),greater<int>());
	for (int i=0;i<V.size();i++)
		if (i&1) ans2+=V[i];
		else ans1+=V[i];
	printf("%d %d\n",ans1,ans2);
	return 0;
}

5.CF388C. Fox and Card Game

题目描述

Solution

答案必然集中在序列的中间几个数中。
先手先进行 k k 次操作会让答案区间平移若干格,直接维护即可。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
 
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
 
using namespace std;
 
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
 
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
 
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
int a[MAXN],dp1[MAXN],dp2[MAXN],ans[MAXN];
int main()
{
	int n=read();
	for (int i=1;i<=n;i++) a[i]=read(),upmax(ans[1],a[i]);
	for (int i=1;i<n;i++) upmax(dp1[min(i,n-i)],max(a[i],a[i+1]));
	for (int i=2;i<n;i++) upmax(dp2[min(i-1,n-i)],max(min(a[i-1],a[i]),min(a[i],a[i+1])));
	for (int i=n/2;i>=1;i--) ans[i<<1]=max(ans[(i+1)<<1],dp1[i]),ans[i<<1|1]=max(ans[(i+1)<<1|1],dp2[i]);
	for (int i=n;i>=1;i--) printf("%d ",ans[i]);
	return 0;
}
发布了94 篇原创文章 · 获赞 6 · 访问量 8554

猜你喜欢

转载自blog.csdn.net/xmr_pursue_dreams/article/details/103433414