Codeforces Round #605 (Div. 3)补题

叽你太美,叽你实在是太美
叽你太美,叽你实在是太美,hiahiahia

咳咳……进入正题

Rating:1361 → 1418,四题末尾,要是手速快一点就好了

本场关键词

手速、贪心、最短路、DP、DP、DP

A. Three Friends

模拟题,我居然四发才过……直接GG

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ll q,a[3];
	cin>>q;
	while(q--)
	{
		for(int i=0;i<3;i++)
			cin>>a[i];
		sort(a,a+3);
		if(a[0]<a[1])
			a[0]++;
		else if(a[1]<a[2]-1)
			a[0]++;
		if(a[0]<a[1])
			a[1]--;
		else if(a[1]<a[2]-1)
			a[1]++;
		if(a[1]<a[2])
			a[2]--;
//		printf("a=%lld,b=%lld,c=%lld\n",a[0],a[1],a[2]);
		ll ans=abs(a[2]-a[1])+abs(a[1]-a[0])+abs(a[2]-a[0]);
		cout<<ans<<endl;
	}
	return 0;
}

B.Snow Walking Robot

题意

机器人有一系列操作指令,可以将这一系列指令从中敲除一些,并将剩下指令打乱顺序。
机器人可以向上、下、左、右走,且必须回到原点,且中间不能重复走到同一位置,且要求删除的指令数最少,输出符合要求的指令。

思路

统计指令数量,绕一个圈,直接贪心

AC代码

#include<bits/stdc++.h>
using namespace std;
char s[100005];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>s;
		int len=strlen(s);
		int cnt=0,a[4]={0};
		for(int i=0;i<len;i++)
			if(s[i]=='U')
				a[0]++;
			else if(s[i]=='D')
				a[1]++;
			else if(s[i]=='L')
				a[2]++;
			else
				a[3]++;
		int x=min(a[2],a[3]),y=min(a[0],a[1]);
		if(x==0)
			y=min(y,1);
		if(y==0)
			x=min(x,1);
		cout<<2*x+2*y<<endl;
		for(int i=0;i<x;i++)
			cout<<"R";
		for(int i=0;i<y;i++)
			cout<<"U";
		for(int i=0;i<x;i++)
			cout<<"L";
		for(int i=0;i<y;i++)
			cout<<"D";
		cout<<endl;
	}
	return 0;
}

C. Yet Another Broken Keyboard

题意

一个字符串s,仅由小写英文字母构成。
Norge想打出所有连续非空子串。
可是,他发现他的键盘坏了,只能打出26字母中的k个。
请求出用这个坏掉的键盘,最多能打出多少个字符串s的连续非空子串。

思路

线性DP,dp[i]表示以s串第i个字符结尾的非法子串数量。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[200005];
bool mp[30];
ll dp[200005];
int main()
{
	ll n,k;
	cin>>n>>k>>s+1;
	for(int i=0;i<k;i++)
	{
		char ch;
		cin>>ch;
		mp[ch-'a']=1;
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		if(!mp[s[i]-'a'])//非法
			dp[i]=i;
		else
			dp[i]=dp[i-1];
		ans+=dp[i];
	}
	cout<<n*(n+1)/2-ans<<endl;
	return 0;
}

D.Remove One Element(1500)

题意

一个长度为n的序列,你可以选择是否删除其中一个元素。
求出操作后序列中可能存在的最长连续严格上升子序列长度。

思路

两次DP
第一次DP求出 d p [ i ] dp[i] 表示以第i个元素结尾的LIS
第二次DP反向求, d p 2 [ i ] dp_2[i] 表示以第i个元素开头的LIS
记录上述过程中最大长度 a n s ans
枚举元素 i i ,当 a i 1 < a i + 1 a_{i-1}<a_{i+1} 时, a n s = m a x ( a n s , d p [ i 1 ] + d p 2 [ i + 1 ] ) ans=max(ans,dp[i-1]+dp_2[i+1])

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[maxn],rec[maxn],dp[maxn],des[maxn];
int main()
{
	int n,m=0;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		if(a[i]>a[i-1])
			dp[i]=dp[i-1]+1;
		else
			dp[i]=1;
		m=max(m,dp[i]);
	}
	for(int i=n;i>=1;i--)
	{
		if(a[i]<a[i+1])
			des[i]=des[i+1]+1;
		else
			des[i]=1;
	}
	for(int i=2;i<n;i++)
		if(a[i-1]<a[i+1])//敲除a[i]
			m=max(m,dp[i-1]+des[i+1]);
	cout<<m<<endl;
	return 0;
}

E.Nearest Opposite Parity(2000)

题意

给出一个长度为 n n 的序列 a a
在位置 i i 时,可以跳到 i + a i i+a_i i a i i-a_i (不越界)
对于每一个位 i i ,你想知道最少需要多少步可以到达一个位置 j j ,使得 a j a_j a i a_i 的奇偶性不同

思路

嘤嘤嘤,这题我一眼就觉得是DP,然后交了一发DFS实现的记忆化搜索,MLE了……
要是做出来就快乐上分了(ノ`Д)ノ
没想到居然是图论……我最短路没学懂,太菜了╥﹏╥…
看了半天大佬们的博客,才有点头绪。
初始化 d i s t dist 为-1,这样输出就不用特判了。
本题我们反向建图 G G ,对点 i i ,我们从 i + a [ i ] i+a[i] i a [ i ] i-a[i] i i 建一条权值为1的边, ( u , v ) (u,v) 含义即为 u u 可到达 v v
然后再正向判断一下每个点 i i ,如果 i i 一步到达奇偶性不同的点,则将 d i s t [ i ] dist[i] 置为1,并将 i i 点加入队列,并且在 G G 上以 i i 为源点进行多源BFS,计算剩下所有能多步到达点某个奇偶性不同节点的节点的距离。
因为每条边权值都为1,很明显后出队的权值不会比之前出队的权值小,可以不用优先队列。
因为之前进行判断,所以 d i s t [ v ] = 1 dist[v]=-1 时,一定没有奇偶性不同节点能一步到达 v v ,所以当前的 x x 点奇偶性一定与出点 v v 点相同, d i s t [ v ] = d i s t [ x ] + 1 dist[v]=dist[x]+1

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[maxn],dist[maxn];
vector<int> G[maxn];
int main()
{
	memset(dist,-1,sizeof(dist));
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	queue<int> QAQ;
	for(int i=1;i<=n;i++)//反向建边
	{
		if(i+a[i]<=n)
			G[i+a[i]].push_back(i);
		if(i-a[i]>=1)
			G[i-a[i]].push_back(i);
	}
	for(int i=1;i<=n;i++)//将所有能一步到位的预处理出来
	{
		int x=i+a[i];
		if(x<=n&&(a[x]^a[i])&1)//奇偶性不同
			dist[i]=1;
		x=i-a[i];
		if(x>=1&&(a[x]^a[i])&1)
			dist[i]=1;
		if(dist[i]==1)
			QAQ.push(i);
	}
	while(!QAQ.empty())
	{
		int x=QAQ.front();
		QAQ.pop();
		for(auto &v:G[x])
			if(dist[v]==-1)//这里没有能一步跳到奇偶性不同的点
			{
				dist[v]=dist[x]+1;
				QAQ.push(v);
			}
	}
	for(int i=1;i<=n;i++)
	{
		cout<<dist[i]<<' ';
	}
	return 0;
}

F. Two Bracket Sequences(2400)

一个DP……
应该不会,以后会了再补……
2019年12月18日11点01分

发布了71 篇原创文章 · 获赞 12 · 访问量 7540

猜你喜欢

转载自blog.csdn.net/Miaplacidus/article/details/103589010