• AGC 033


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

    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

      太神仙了,咕咕咕……

    总结

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

    HAHA
  • 相关阅读:
    docker实战~构建并测试web应用(4)
    如何判断系统的性能
    浅析微前端方案及qiankun介绍与开发实践
    记一次阿里云oss文件上传服务假死
    android高级UI之PathMeasure<三>Path测量实战(笑脸loading效果实现、划船效果实现)
    ios从入门到放弃之C基础巩固宏定义、条件编译、文件包含、typedef、const关键字
    ios从入门到放弃之C基础巩固结构体、枚举、全局变量和局部变量、static和extern
    fsdfd
    C++中sort()函数使用介绍
    git fork
  • 原文地址:https://www.cnblogs.com/hahamengbier/p/AGC033.html
Copyright © 2020-2023  润新知