Codeforces Round #699(div2 A~E) 补题

链接

http://codeforces.com/contest/1481

A. Space Navigation

(rating : 800)
题意:一个机器人要从坐标系上的(0,0)走到(i,j) 。 给一串由u,d,l, r (上下左右)组成的字符串代表初始设定的走法。问能否通过删去一些字符,让机器人能成功地走到(i,j),输出 yes or no 。

思路:从(0,0)到(i,j),就是横着走 i步 ,纵着走j步。 只需要判断下 l 和 r 的数目能否凑出 i , u 和 d 的数目能否凑出j 即可。

B. New Colony

(rating: 1100)
题意:现在有一排山,高度为h1,h2,h3 … hn 。把一个石头放在第一座山上 , 如果当前第i座山的高度不小于第i+1座山的高度 , 那么石头就会滚到第i+1座山上;否则,石头会留在第i座山上,并使第i座山高度+1 。当石头滚到最后一座山时,会自动滑落并消失 。 问 : 现在依次放上 k 个石头,第k个石头会滑到第几座山上 。

思路:按题目要求模拟即可 。 当第i座山高度等于第i+1座山时,把它们看成一个整体 , 接着向后遍历 。 当第i座山高度小于第i+1座时 , 该山就会被一直垫高直到石头用完 或者 高度 = min(h[i-1],h[i+1]) 。

C. Fence Painting

(rating:1600)
题意:有n面墙,它们的颜色是 a1, a2, a3 … an 。 但是户主希望它们的颜色是 b1,b2,b3 … bn
现在有m位粉刷匠以时间顺序前来 , 每人带着一个油漆桶 ,颜色是 c1,c2, c3 … cm。每一个粉刷匠到来的时候,只能选择粉刷一面墙 , 而且你必须让他们粉刷一面墙 。 问这m位粉刷匠能否将这n面墙都变成户主期望的颜色 。

思路:把需要改变颜色的墙的信息储存起来 。 然后从后往前遍历粉刷匠 , 其中最后一位粉刷匠携带的颜色必须是需改变的墙的颜色 。对于之前的粉刷匠,如果没有任务,就让它去粉刷之后的粉刷匠会改变的颜色。(例如,最后一个粉刷匠会把第5面墙从红色变成期望的蓝色 , 那么在它之前没有任务的粉刷匠就可以派去随便刷第5面墙)。最后,再判断一下是否所有的墙都是期望的颜色即可。

代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+5;
    int a[maxn],b[maxn],c[maxn],ans[maxn],cnt;vector<int> v[maxn];
    int main(){
    	int t;
    	cin>>t;
    	while(t--){
    		int n,m;cnt = 0;
    		scanf("%d %d",&n,&m);
    		for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    		for(int i=1;i<=n;i++)
    		scanf("%d",&b[i]);
    		for(int i=1;i<=m;i++)
    		scanf("%d",&c[i]);
    		for(int i=0;i<=n;i++){
    			while(v[i].size()!=0)
    			v[i].pop_back();
    		}
    		for(int i=1;i<=n;i++){
    			if(a[i]!=b[i])
    			v[b[i]].push_back(i);
    		}
    		
    		int able = -1;bool flg = 1;
    		for(int i=1;i<=n;i++){
    			if(b[i]==c[m]){
    			able = i;break;
    			}
    		}
    		for(int i=m;i>=1;i--){
    			//cout<<c[m]<<endl;
    			int now = c[i];
    			if(v[now].size()==0){
    				if(able==-1){
    					flg = 0;
    					break;
    				}
    				else{
    					ans[cnt++] = able;
    				}
    			}
    			else{
    				int save = v[now].back();
    				v[now].pop_back();
    				ans[cnt++] = save;
    				able = save;
    			}
    		}
    		if(flg==0){
    			printf("NO\n");
    		}
    		else{
    			for(int i=0;i<=n;i++){
    				if(v[i].size()!=0)
    				flg = 0;
    			}
    			if(flg==0)
    			printf("NO\n");
    			else{
    				printf("Yes\n"); 
    				for(int i=cnt-1;i>=0;i--)
    				printf("%d ",ans[i]);
    				printf("\n");
    			}
    		
    		}
    	}
    } 

D. AB Graph(图论)

(rating:2000)
在这里插入图片描述

题意:给一个有向完全图 。图中每一条边都随机赋一个字母a 或 b 。 问题是 : 在图中找到一条路径(可重复边重复点),使得该路径是一个长度为m的回文串。

思路
用a[i][j] 来存储 i --> j 这条边赋了哪个字母 。
1.当回文串长度为奇数时,显然我们只需要在两点之间反复横跳即可。因为无论是aaaaa这样的,或是ababa这样的 ,在奇数情况下都一定回文。
2.另外可以发现 ,如果存在两点i,j, a[i][j] = a[j][i] , 那么在i,j之间反复横跳取的就是同一个字母,必定回文。
3.当上述情况不满足时,m = 2肯定不成立 ,如题中样例 。
4.那么就剩下一种最难的情况,m是偶数 , 且不满足第2点。
这时要满足回文,就必须找到一个点 y ,使得存在a[x][y] = a[y][z] 。 也就是,存在一个x–>y被赋予的字母 与 y—> z被赋予的字母相同 。 然后让y–>z,x–>y分别作为字符串的首尾 , 中间是 z—>x,x—>z ,z—>x 的反复横跳 。
对于寻找这样的点y,我们不必访问整张图 , 因为题目说了这是个有向完全图,每个点都与别的点相连。 只需要任意取3个点,如果它们的全排列都不满足a[x][y] = a[y][z] , 那么整张图也无此点。

代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    char a[1005][1005];
    void solve(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if(i==j) continue;
    			if(a[i][j]==a[j][i]){
    				printf("YES\n");
    				//printf("%d ",i);
    				for(int k=0;k<=m;k++)
    					printf("%d ",(k%2)==0?i:j);
    					printf("\n");
    				return;
    			}
    		}
    	}
    	if(m%2==1){
    		printf("YES\n");
    		int x = 1,y = 2;
    			for(int k=0;k<=m;k++){
    				printf("%d %d ",x,y);k++;
    			}printf("\n");
    		return;
    	}
    	if(n==2){
    		printf("NO\n");
    		return;
    	}
    	else{
    		int b[6][3] = {{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}};
    		for(int i=0;i<6;i++){
    			int x = b[i][0],y = b[i][1],z = b[i][2];
    			if(a[x][y]==a[y][z]){
    				printf("YES\n");
    				int len = m/2;
    				if(m%4==0){
    					for(int k=0;k<len;k+=2){
    						printf("%d %d ",y,z);
    					}
    					printf("%d ",y);
    					for(int k=0;k<len;k+=2){
    						printf("%d %d ",x,y);
    					}
    					printf("\n");
    				}
    				else{
    					for(int k=0;k<len;k++){
    						if(k%2==0)
    						printf("%d ",z);
    						else
    						printf("%d ",y);
    					}
    					printf("%d ",y);
    					for(int k=0;k<len;k++){
    						if(k%2==0)
    						printf("%d ",x);
    						else
    						printf("%d ",y);
    					}
    					printf("\n");
    				}
    				return;
    			}
    		}
    		printf("NO\n");
    		return;
    	}
    }
    int main(){
    	int t;
    	cin>>t;
    	while(t--){
    		cin>>n>>m;
    		for(int i=1;i<=n;i++){
    			cin>>a[i]+1;
    		}
    		solve();
    	}
    }

E. Sorting Books(动态规划)

(rating:2500)
在这里插入图片描述

题意:书架上有一排书,每本书都有一个颜色ai ,要求最小化操作次数 , 使得相同颜色的书摆在一起。 你所能做的操作是:每次取出一本书,把它放在这排书最右边。(n<=5e5)

思路:这是道非常好的DP题,但是很难,结合好几篇题解想了好久才想通~~

我的想法大致如下:

既然是只能往右边放,那最好就从右往左遍历这排书。设dp[i] 表示对于第i到第n本书,不需要操作的次数,最终结果即n - dp[1]。

假设第i本书是红色,要最小化此时的操作次数:
1)要么对该书操作,把该书往后扔 , 其余的继承之前的最优解 ,也就是dp[i] = dp[i+1] 。

2)要么把之后的所有红书留下,其他非红书的往后扔,此时如果该红色书是最左端的红色书,那么也就是dp[i] = color[红色] + dp[最右端的红色书+1] 。如果不是最左端的红色书,那么dp[i] = color[红色]。(color[红色] 顾名思义,指到目前为止红色书的数量)
两种情况取max。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int a[maxn],color[maxn],dp[maxn];
struct node{
	int l;
	int r;
}b[maxn];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(b[a[i]].l==0) b[a[i]].l = i;
		b[a[i]].r = i;
	}
	for(int i=n;i>=1;i--){
		dp[i] = dp[i+1];
		color[a[i]]++;
		if(i==b[a[i]].l)
		dp[i] = max(dp[i],dp[b[a[i]].r+1]+color[a[i]]);
		else
		dp[i] = max(dp[i],color[a[i]]);
	}
	cout<<n - dp[1]<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值