AGC 033

  题目有点神仙,被虐爆了。

A. Darker and Darker

  \(Bfs\) 水题,没用,不写了。

B. LRUD Game

题面

LRUD Game
  有一个 \(n\times m\) 的棋盘,横纵坐标均从 \(1\) 开始标号。上面有一个棋子,有两个人在挪动这个棋子,每个人有一个长度为 \(q\) 的操作序列(由 \(L,R,U,D\) 组成),第 \(i\) 个字母表示 \(i\) 时刻可以进行这个操作(也可以不进行,但不能进行别的操作)。第一个人想要把棋子移到棋盘以外,第二个人则相反,第一个人先手,两人都绝顶聪明,问最后谁能赢。

题解

   \(\text{B}\) 题我就不会了, \(chr\) 一眼秒了, \(Orz\ Asttinx64\)
   感觉这题就很套路,然而我并不会。
   首先比较显然的是,我们可以对 \(L,R\)\(U,D\) 分开单独考虑。考虑对第二个人维护一个必胜区间(一定是连续的),然后倒序操作,根据当前的人可作出的操作来改变该必胜区间的左右端点,最后直接判断就行了。

代码

#include <cmath>
#include <ctime>
#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define debug(...) fprintf(stderr,__VA_ARGS__)

typedef long long LL;
typedef unsigned int uint;
typedef std::vector<int> vi;
typedef unsigned long long uLL;
template<typename T> inline void I(T &x){
	register int ch,k=1;
	while(ch=getchar(),ch<'/')k=(ch=='-' ? -1 : k);x=ch-'0';
	while(ch=getchar(),ch>'/')x=((x+(x<<2))<<1)+ch-'0';x*=k;
}

const int maxn=2e5+7;
int n,m,L;
int sx,sy;
char a[maxn];
char b[maxn];
int main(){
	scanf("%d%d%d%d%d%s%s",&n,&m,&L,&sx,&sy,a+1,b+1);
	{
		int s=1,t=n;
		for(int i=L;i;--i){
			if(b[i]=='U' || b[i]=='D'){
				if(b[i]=='U')
					t=std::min(t+1,n);
				else s=std::max(s-1,1);
			}
			if(a[i]=='U' || a[i]=='D'){
				if(a[i]=='U')++s;
				else --t;
			}
			if(s>t)return!puts("NO");
		}
		if(sx<s || t<sx)
			return!puts("NO");
	}{
		int s=1,t=m;
		for(int i=L;i;--i){
			if(b[i]=='L' || b[i]=='R'){
				if(b[i]=='L')t=std::min(t+1,m);
				else s=std::max(s-1,1);
			}
			if(a[i]=='L' || a[i]=='R'){
				if(a[i]=='L')++s;
				else --t;
			}
			if(s>t)return!puts("NO");
		}
		if(sy<s || t<sy)
			return!puts("NO");
	}puts("YES");
	return 0;
}

C. Removing Coins

题面

Removing Coins
  给一棵 \(n\) 个点的树,每个节点上有个硬币,有两个人在玩游戏,每个人交替进行如下操作:
   1. 选一个有硬币的点 \(x\) ,并把这个节点上的所有硬币拿走;
   2. 对于其他的每个有硬币的点 \(y(y\neq x)\) ,把 \(y\) 上的所有硬币移到相邻节点中靠近 \(x\) 的节点上;
  第一个人先手,拿走最后一摞硬币的人获胜,问谁必胜。

题解

  这题也好 \(\text{NB}\) ,并且我还看错题了,看了题解发现做的不是同一道题……
  首先考虑链的情况,每次操作在剩余点数 \(n'>2\) 时,相当于删掉一个或两个端点,就转化成了某个经典模型,那么先手必败条件就是 \(n\!\!\!\!\mod\!\!3=2\)
  推广到树上,不难想到就是由最长链(直径)的长度 \(len\) 来决定,大家可以感性理解。
  博弈论好玄学啊……

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
const int maxn=2e5+7;
struct Edge{
	int to;
	int last;
}a[maxn<<1];
int n,m;
int tot;
int d[maxn];
int head[maxn];
inline void HA(int x,int y){
	a[++tot]=(Edge){y,head[x]};head[x]=tot;
	a[++tot]=(Edge){x,head[y]};head[y]=tot;
}
#define y a[i].to
inline void Dfs(int x,int prt){
	for(int i=head[x];i;i=a[i].last)
		if(y!=prt)d[y]=d[x]+1,Dfs(y,x);
	if(d[x]>d[m])m=x;
}
#undef y
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<n;++i)
		scanf("%d%d",&x,&y),HA(x,y);
	m=0,Dfs(1,0);
	int temp=m;d[m]=0;
	m=0,Dfs(temp,0);
	puts(d[m]%3==1 ? "Second" : "First");
	return 0;
}

D. Complexity

题面

Complexity
这个题意挺好懂的,我就不翻译了。

题解

  这个题也不错,但是有点诡异。
  首先答案比较小,大概在 \(\log(HW)\) 的水平,那么我们就可以枚举答案了,考虑如何 \(\text{DP}\) 来检验答案。
  我们可以发现,权值的贡献很像倍增,这也是为什么答案是 \(\log\) 级别的原因。定义 \(fl[d][x][y][xx]\) 表示答案为 \(d\) 时从 \((x,y)-(xx,y)\) 能向左延伸的最大长度,那我们就可以从上一层转移到下一层,转移就是直接拼起来,类似地还要定义 \(fu[d][x][y][yy]\) ,然后 \(fl,fu\) 之间还要相互转移。复杂度大概是 \(\Theta(n^2m^2\log(nm))\)
  我们就可以直接 for(int ans=0;"Jumbo tql";++ans) 来枚举 \(ans\)\(\text{DP}\) 了,终止条件根本没有,因为 Jumbo tql 是真理就是 fl[1][m][n]==m

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
const int maxn=185+3;
int n,m;
int c[maxn][maxn];
int L[maxn][maxn];
int U[maxn][maxn];
int fl[maxn][maxn][maxn];
int fu[maxn][maxn][maxn];
int gl[maxn][maxn][maxn];
int gu[maxn][maxn][maxn];
char ch;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j){
			scanf(" %c",&ch),c[i][j]=(ch=='#');
			L[i][j]=(j==1 ? 1 : (c[i][j-1]==c[i][j] ? L[i][j-1]+1 : 1));
			U[i][j]=(i==1 ? 1 : (c[i-1][j]==c[i][j] ? U[i-1][j]+1 : 1));
		}
	for(int x=1;x<=n;++x)
		for(int y=1;y<=m;++y){
			for(int xx=x,Min=666;xx<=n;++xx){
				if(xx>x && c[xx][y]!=c[xx-1][y])Min=0;
				fl[x][y][xx]=Min=std::min(Min,L[xx][y]);
			}
			for(int yy=y,Min=666;yy<=m;++yy){
				if(yy>y && c[x][yy]!=c[x][yy-1])Min=0;
				fu[x][y][yy]=Min=std::min(Min,U[x][yy]);
			}
		}
	for(int ans=0;"Jumbo tql";++ans){
		if(fl[1][m][n]==m || fu[n][1][m]==n)
			return printf("%d\n",ans),0;
		memcpy(gl,fl,sizeof(gl));
		memcpy(gu,fu,sizeof(gu));
		for(int x=1;x<=n;++x)
			for(int y=1;y<=m;++y){
				for(int xx=x;xx<=n;++xx)fl[x][y][xx]+=gl[x][y-gl[x][y][xx]][xx];
				for(int yy=y;yy<=m;++yy)fu[x][y][yy]+=gu[x-gu[x][y][yy]][y][yy];
			}
		for(int x=1;x<=n;++x)
			for(int y=1;y<=m;++y){
				for(int xx=x,X=1;xx<=n;++xx,++X)
					for(int yy=y-fl[x][y][xx]+1;yy<=y && fu[xx][yy][y]<X;++yy)
						fu[xx][yy][y]=X;
				for(int yy=y,Y=1;yy<=m;++yy,++Y)
					for(int xx=x-fu[x][y][yy]+1;xx<=x && fl[xx][yy][x]<Y;++xx)
						fl[xx][yy][x]=Y;
			}
	}return 0;
}

E. Go around a Circle

  看不懂题,不想写了。

F. Adding Edges

  太神仙了,咕咕咕……

总结

  第一次打比赛就被虐爆了,考的题目思维含量都挺高的,我这种辣鸡有点吃力啊,以后多加练习吧。

posted @ 2019-06-02 11:29  mengbier  阅读(375)  评论(0编辑  收藏  举报