CF Educational Round 168(Div.2)题解(A~D)

A-Strong Password(字符串 构造 贪心)

题意

给定一个由小写字母组成的字符串密码,定义一个密码的复杂度(输入时间):第一个字母需要两秒,其他字母如果与前一个字母相同,需要1秒,否则需要2秒,现在要求在字符串中插入任意一个小写字母使得输入时间最大(这里的better翻译错误,翻译为了最短时间),输出插入后的字符串

思路

直接从左往右遍历,直到找到两个连续相同的字母,在中间插入一个不同的字母即可,如果没有则加在字符串末尾,与字符串末尾的字母不同

代码

	#include <iostream>
	#include <cstring>
	#include <queue>
	#include <map>
	#include <set>
	#include <algorithm>
	#include <cmath>
	#include <vector>
	#include <stack>
	using namespace std;
	typedef long long LL;
	typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
	const LL N=1e5+10;
	const LL INF=1e18;
	const double small=1e-16;
	//千万不要用puts()和gets(),求求你了 
	
	
	void solve()
	{
		string s;
		cin>>s;
		int n=s.size();
		bool flag=false;
		if(n==1)
		{
			if(s[0]=='a')cout<<"ab"<<endl;
			else cout<<s[0]<<(char)(s[0]-1)<<endl;//这里有个坑:char减去1会被转化为int类型,需要转化回来
			return;
		}
		for(int i=0;i<s.size()-1;i++)
		{
			cout<<s[i];
			if(s[i]==s[i+1]&&flag==false)
			{
				flag=true;
				char tmp=s[i];
				if(tmp=='a')tmp++;
				else tmp--;
				cout<<tmp;
				flag=true;
			}
		}
		cout<<s[s.size()-1];
		if(!flag)
		{
			char tmp=s[s.size()-1];
				if(tmp=='a')tmp++;
				else tmp--;
				cout<<tmp;
		} 
		cout<<endl;
	}
	
	int main()
	{
	    
		int t=1;
		cin>>t;
		while(t--)
		{
			solve();
		}
		return 0;
	}

B-Make Three Regions(构造)

题意

给定一个2*n的矩阵,里面由两种方块组成:堵塞方块和自由方块,自由方块有且只会形成一个联通块(这个条件很重要),求符合条件的自由方块个数(把这个自由方块变成堵塞方块后恰好能把一个联通块割成3个联通块)

思路

因为自由方块有且只会形成一个联通块,所以只会有一种结构能够满足分割条件:

(黑色的是堵塞方块,白色的是自由方块,有点潦草,可以上下颠倒为另一种情况)

然后特判累加即可

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
char s[3][N];

void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>s[1][i];
	for(int j=1;j<=n;j++)cin>>s[2][j];
	if(n<3)
	{
		cout<<"0"<<endl;
		return;
	}
	LL res=0;
	for(int i=1;i+2<=n;i++)//两种特判
	{
		if(s[1][i]=='x'&&s[1][i+2]=='x'&&s[1][i+1]=='.')
		{
			if(s[2][i]==s[2][i+1]&&s[2][i+1]==s[2][i+2]&&s[2][i+2]=='.')
			{
				res++;
			}
		}
		if(s[2][i]=='x'&&s[2][i+2]=='x'&&s[2][i+1]=='.')
		{
			if(s[1][i]==s[1][i+1]&&s[1][i+1]==s[1][i+2]&&s[1][i+2]=='.')
			{
				res++;
			}
		}
	}
	cout<<res<<endl;
}

int main()
{
    
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

C-Even Positions(数据结构-栈 构造 贪心)

题意

给定一个由'(',')'和'_'三种字符组成的字符串,'_'出现在所有的奇数位,现在需要我们在'_'中填入'('或')',使得每个括号一定能够配对(保证一定存在这样的字符串),使得字符串的分数最大(每个括号左右下标差的累加值)

思路

看到括号,就想到栈的使用,这道题的解法多样,我的解法使用了栈;

枚举原字符串,一共有三种字符,分别进行操作:

具体逻辑在代码中注释出来了

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<char,LL> PII;//开long long,求求你了,记得开long long 
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
char s[N];

void solve()
{
	LL n;
	cin>>n;
	stack<PII> q;
	for(int i=1;i<=n;i++)cin>>s[i];
	LL res=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='_')//碰到'_'
		{
			if(q.size()&&(q.top().first=='('))//如果栈顶为左括号,优先满足
			{
				
				res+=(i-q.top().second);//配对成功
				q.pop();
			}
			else//否则入栈等待右括号
			{
				q.push({'_',i});
			}
		}
		else if(s[i]=='(')//碰到'('
		{
			q.push({'(',i});//直接入栈,等右边的‘_’
		}
		else if(s[i]==')')//碰到')'
		{
		    //if(q.size())cout<<q.top().first<<endl;
			if(q.size()&&(q.top().first=='('||q.top().first=='_'))'('和‘_’都可以配对
			{
				
				res+=(i-q.top().second);//配对成功
				q.pop();
			}
		}
	}
	//cout<<q.size()<<endl;//这里看到栈到后面总是空的,不用再处理了
	cout<<res<<endl;
}

int main()
{
    
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

D-Maximize the Root(带权树 dfs min)

题意

给定一个以1为根节点,共有n个带权顶点的树,可以对至少有一个子节点的顶点进行操作,将这个顶点的后代节点(包括子顶点、孙顶点等)的权值-1,该顶点权值+1(但是要保证每个顶点的权值都不为负数),求经过若干这种操作后,顶点1的权值的最大值。

思路

这道题赛时没有A出来,当时想到了dfs求子树最小值这种做法,但是因为能够加1的不只是根节点,所以单纯取最小值是不行的,非1顶点也可以通过压榨权值比它大的子节点+1,所以需要考虑子树中子节点最低权值比父节点权值大的情况,赛后看到大佬的平均写法,真的太妙了(我还是太蒻了)

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long 
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
int p[N];
int h[N];
int e[N];
int ne[N];
int idx=0;

void add(int a,int b)//邻接表存图
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}

int dfs(int u)
{
	int hh=p[u];//当前节点的初始权值
	LL t=1e17;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		int tmp=dfs(j);//遍历每一个子节点,找到最小权值
		t=min((LL)tmp,t);
	}
	if(u==1)//到根节点,直接加上当前最新的子节点的最小值
	{
		if(t!=1e17)
		{
			hh+=t;
		}
		cout<<hh<<endl;
		return 0;
	}
	if(t!=1e17&&t>=hh)//子节点比父节点权值大,说明可以通过若干操作进行平均,增大父节点的权值
	{
		hh=(hh+t)/2;//取平均
	}
	if(hh>t)
	{
		hh=t;//如果子节点权值比父节点还小,就不能操作,而且会降低这棵树的最低权值
	}
	return hh;
}

void solve()
{
	memset(h,-1,sizeof h);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>p[i];//初始权值
	for(int i=2;i<=n;i++)
	{
		int x;
		cin>>x;
		add(x,i);
	}
	dfs(1);
	
}

int main()
{
    
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

E-Level Up

F-Chips on a Line

窝滴水平不足,剩下的两题补不了,先放个传送门,以后再补。

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值