题目有点神仙,被虐爆了。
A. Darker and Darker
(Bfs) 水题,没用,不写了。
B. LRUD Game
题面
LRUD Game
有一个 (n imes m) 的棋盘,横纵坐标均从 (1) 开始标号。上面有一个棋子,有两个人在挪动这个棋子,每个人有一个长度为 (q) 的操作序列(由 (L,R,U,D) 组成),第 (i) 个字母表示 (i) 时刻可以进行这个操作(也可以不进行,但不能进行别的操作)。第一个人想要把棋子移到棋盘以外,第二个人则相反,第一个人先手,两人都绝顶聪明,问最后谁能赢。
题解
( ext{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
eq x)) ,把 (y) 上的所有硬币移到相邻节点中靠近 (x) 的节点上;
第一个人先手,拿走最后一摞硬币的人获胜,问谁必胜。
题解
这题也好 ( ext{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)) 的水平,那么我们就可以枚举答案了,考虑如何 ( ext{DP}) 来检验答案。
我们可以发现,权值的贡献很像倍增,这也是为什么答案是 (log) 级别的原因。定义 (fl[d][x][y][xx]) 表示答案为 (d) 时从 ((x,y)-(xx,y)) 能向左延伸的最大长度,那我们就可以从上一层转移到下一层,转移就是直接拼起来,类似地还要定义 (fu[d][x][y][yy]) ,然后 (fl,fu) 之间还要相互转移。复杂度大概是 (Theta(n^2m^2log(nm))) 。
我们就可以直接 for(int ans=0;"Jumbo tql";++ans)
来枚举 (ans) 并 ( ext{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
",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
太神仙了,咕咕咕……
总结
第一次打比赛就被虐爆了,考的题目思维含量都挺高的,我这种辣鸡有点吃力啊,以后多加练习吧。