暑假训练第一天 (vp atcoder test 303(A-E))

A题:判断两个字符串是不是相似

注意特判:l 和 1,o和0

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
void cf()
{
	ll n;
	cin>>n;
	string s1,s2;
	cin>>s1>>s2;
	bool ok=false;
	for(int i=0;i<n;i++)
	{
		if(s1[i]!=s2[i])
		{
			if((s1[i]=='1'&&s2[i]=='l')||(s1[i]=='l'&&s2[i]=='1'))continue;
			if((s1[i]=='0'&&s2[i]=='o')||(s1[i]=='o'&&s2[i]=='0'))continue;
			ok=true;
		}
	}
	cout<<(ok==true?"No":"Yes")<<endl;
	 
}
	 
	//123
	//139
	
	//12399
	//12400

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

B题:

有n个人,m张照片,求和每个人不相邻的总对数

直接模拟:n个人总的相连对数是n*(n-1)/2,只要找出相连的然后总数再减去就可以了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int check[60][60];
ll a[100];
void cf()
{
	ll n,m;
	memset(check,0,sizeof check);
	cin>>n>>m;
	while(m--)
	{
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n-1;i++)
	{
		check[a[i]][a[i+1]]=1;
	}
	}
	ll sum=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			if(check[i][j]||check[j][i])sum++;
		}
	}
	ll ans=n*(n-1)/2;
	cout<<ans-sum<<endl;
}
	 
	//123
	//139
	
	//12399
	//12400

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

C题:纯模拟

给你一个字符串,u代表向上走,d代表向下,l代表向左,r代表向右,一个人的初始生命是h,在地图上有m个点有药剂,如果一个人的血量低于k可以把生命回复到k,但是一旦生命小于0就不可以再走了,每次实现字符串的一个操作要减少一个生命,问有没有可能走完字符串的所有操作

这题因为地图的n,m都在2e5所以用传统的二维数组存图是不行的我们可以用stl里面的set和pair<int,int>来存坐标,然后就是纯模拟了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void cf()
{
	ll n,m,h,k;
	cin>>n>>m>>h>>k;
	string s;
	cin>>s;
	//n是字符串的长度
	//m个坐标
	//h是初始的生命值
	//生命值小于k会回复到k
	set<pair<int,int>>st;
	int bex=0,bey=0;
	 while(m--)
	 {
	 	int x,y;
	 	cin>>x>>y;
	 	st.insert({x,y});
	 }
	 bool ok=false;
	 for(auto i:s)
	 {
	 	if(i=='L')
	 	{
	 		bex--;
		}
		if(i=='R')
		{
			bex++;
		}
		if(i=='U')
		{
			bey++;
		}
		if(i=='D')
		{
			bey--;
		}
		h--;
		if(h<0)
		{
			ok=true;
			break;
		}
		else if(h<k)
		{
			if(st.count({bex,bey}))
			{
				h=k;
				st.erase({bex,bey});
			}
		 } 
		
	 }
	 cout<<(ok==true?"No":"Yes")<<endl;
	 
	 
}
	 
	//123
	//139
	
	//12399
	//12400

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

D题:题目大意:

Syx 是一个码农,但她的键盘不太一样,她的键盘仅由大小写的 aShiftCaps lock 组成。

如果 Syx 按下 a 键,则会打出 a,并耗费 xx 的时间。

如果她按下 Shift + a 键,则会打出大写的 A(若开启 Caps lock 则是 a),耗费 yy 的时间。

如果按下 Caps lock,则会开启/关闭大写锁定,耗费 zz 的时间。

现在她想打出一个字符串 ss,请问最少耗时是多少。

dp做法:

dp[i][0]表示打第i个字符时候大写锁定是关的最小时间
dp[i][1]表示打第i个字符时候大写锁定是开的最小时间

我们想要打出a的话有两种情况锁定不开的话直接花费x按a键

如果锁定开的话要shift+a才可以,如果直接按a键的话打出来是A

打A的话也有两种情况一种是锁定开的时候直接按a键就行

如果锁定关的话我们可以shift+a或者先开锁定再按a键

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e7+10; 
ll dp[N][2];
//dp[i][0]表示打第i个字符时候大写锁定是关的最小时间
//dp[i][1]表示打第i个字符时候大写锁定是开的最小时间
string s;
void cf()
{
	ll x,y,z;
	cin>>x>>y>>z;
	cin>>s;
	//按下a键花费x的时间
	//按下shift+a键花费y的时间
	//关闭大写锁定(按下)caps lock花费y的时间
	if(s[0]=='a')
	{
		dp[0][0]=x;//最开始锁定的关的如果第一个字符是a的话我们可以直接打时间花费是x
		dp[0][1]=y+z;//这个时候锁定是关着(花费z)的所以想要打出a的话要按shift+a(花费y)
	}
	else if(s[0]=='A')
	{
		dp[0][0]=y;
		dp[0][1]=z+x; 
	}
	ll len=s.size();
	for(int i=1;i<len;i++)
	{
		if(s[i]==s[i-1])
		{
			if(s[i]=='a')
			{
				dp[i][0]=min(dp[i-1][0]+x,dp[i-1][1]+z+x);
				//以dp[i][0]为例子 
				//如果之前锁定是关的并且前面一个字符也是a那直接按a键就可以打a
				//如果之前锁定是开的那我们必须先把锁定关掉因为下一个字符锁定是关的说明我们肯定要关然后直接按a键打a花费x 
				dp[i][1]=min(dp[i-1][0]+z+y,dp[i-1][1]+y);
			}
			else if(s[i]=='A')
			{
				dp[i][0]=min(dp[i-1][0]+y,dp[i-1][1]+y+z);
				dp[i][1]=min(dp[i-1][0]+z+x,dp[i-1][1]+x);
			}
		}
		else
		{
			if(s[i-1]=='a')
			{
				//是s[i]='A'
				dp[i][0]=min(dp[i-1][0]+y,dp[i-1][1]+z+y);
				dp[i][1]=min(dp[i-1][0]+z+x,dp[i-1][1]+x);
			}
			else if(s[i-1]=='A')
			{
				//是s[i]='a' 
				dp[i][0]=min(dp[i-1][0]+x,dp[i-1][1]+z+x);
				dp[i][1]=min(dp[i-1][0]+z+y,dp[i-1][1]+y);
			}
		}
	} 
	cout<<min(dp[len-1][1],dp[len-1][0])<<endl;
	 
	 
	 
}
	 
	//123
	//139
	
	//12399
	//12400

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

E题

题目大意(参照洛谷翻译)

一个具有 (k+1) 个顶点和 kk 条边的图被称为一个级别为 k(k≥2))的菊花图,当且仅当:

  • 它有一个顶点与其他 k 个顶点之间通过一条边相连,而其他顶点之间没有边。

起初,我们有一个由多个菊花图组成的图。重复以下操作,直到整个图变为一张连通图:

  • 选择图中的两个顶点。其中顶点之间必须是不连通的,并且它们的度数必须都是 11。将这两个顶点用一条边连接起来。

然后,在该过程后,他将整数从 1 到 N 随机分配给图中的每个顶点。生成的图是一棵树,我们称其为 T。T 有 (N−1) 条边,第 i 条边连接了 ui和 vi。

给定 T,从小到大输出一开始的每个菊花图的 k。

我们知道一个菊花图的中心节点度数一定是大于2的那我们直接统计一下度数然后从大到小排列,因为一共有n个节点,每k级菊花图花费k+1个节点我们只需要每次减去(du[i]+1)就行

当然可能有度数1的点,这些点最后其实都是作为叶子和其他叶子连边构成联通所以不用管,我们只需要在最后输出答案的时候加个判断就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+10;
ll du[N];
ll ans[N];
ll cnt=0; 
void cf()
{
	ll n;
	cin>>n;
	ll tes=n-1;
	while(tes--)
	{
		int x,y;
		cin>>x>>y;
		du[x]++;
		du[y]++;
	}
	sort(du+1,du+1+n,greater<int>());
	for(int i=0;n>0;i++)
	{
		n-=(du[i]+1);
		//度数大于等于2的一定是菊花图的中心
		//k等级的菊花图花费(k+1)个顶点
		ans[cnt++]=du[i]; 
	}
	for(int i=cnt;i>=0;i--)
	{
		if(ans[i]>1)cout<<ans[i]<<" ";
	}
	 
	 
}
	 
	//123
	//139
	
	//12399
	//12400

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值