Educational Codeforces Round 161 (Rated for Div. 2) A~D

a

题意:给你三个长度为 n n n 的由小写字母构成字符串 a 、 b 、 c a、b、c abc 。字符串 t t t 是由长度为 n n n 由大、小写字母构成的字符串。若字符串 s s s 满足从1~n满足以下条件,则称字符串 s s s 和字符串 t t t 匹配

  • t i t_i ti 为小写字母 , 则 s i = t i s_i=t_i si=ti
  • t i t_i ti 为大写字母 , 则 s i s_i si 不能为 t i t_i ti 所对应的小写字母 。

是否存在模板 t t t ,使字符串 a a a b b b 与其匹配,而字符串 c c c 不匹配。

思路:如果 c i c_i ci 不等于 a i a_i ai c i c_i ci 不等于 b i b_i bi ,那我们可以构造 t i t_i ti c i c_i ci 所对应的大写字母。

void solve()
{
	string a,b,c;
	int n;
	cin>>n>>a>>b>>c;
	for(int i=0; i<n; i++)
	{
		if(a[i]!=c[i] && b[i]!=c[i])
		{
			puts("YES");	return ;
		}
	}
	puts("NO");
}

b

题意:n根木棍,每根木棍长度为 2 a i 2^{a_i} 2ai,问你有多少种方法构成三角形(不考虑顺序)。
思路:考虑特殊情况:

  • 当组成的三角形为等边三角形的时候,取三根相同的木棍。
  • 当组成的三角形为等腰三角形的时候(腰长选取的为 2 a 2^{a} 2a ),取两根相同的,根据两边之和要大于第三边 2 a 2^{a} 2a + 2 a 2^{a} 2a = 2 a + 1 2^{a+1} 2a+1 > 2 c 2^c 2c ,而且第条三边不能和前两条边相同,所以第三条边的范围 (0,a-1]。(a为等腰三角形的边长)。
  • 当组成普通三角形的时候,可以证明不能组成三角形——假设边长关系为 2 a 2^{a} 2a > 2 b 2^{b} 2b > 2 c 2^{c} 2c,由于任意两边之和要大于第三遍,但是 2 a 2^{a} 2a + 2 b 2^{b} 2b < 2 c 2^{c} 2c,故组成不了三角形。
void solve()
{
	int n;	cin>>n;
	vector<ll> cnt(n+1,0);
	for(int i=1; i<=n; i++)
	{
		int c;	cin>>c;		cnt[c]++;
	}

	ll ans = 0 , tot = 0;	//tot记录当前比它小的棒的个数

	for(int i=0; i<=n; i++)
	{
		//选两个相同的和一个小于他的
		if(cnt[i]>=2)
			ans += cnt[i]*(cnt[i]-1)/2*tot;
		if(cnt[i]>=3)
			ans += cnt[i]*(cnt[i]-1)*(cnt[i]-2)/6;
		tot += cnt[i];
	}
	
	cout << ans << '\n';

}
c

题意:由 n n n个城市在数轴上, a i a_i ai表示第 i i i个城市在数轴上的位置,两个城市之间的距离等于| a i a_i ai- a j a_j aj|,每个城市到达距离它最近的城市需要花费1金币,到达其它城市需要花费的金币等于他的距离,给你 m m m个询问,问你每次从 x x x y y y最少需要花费多少个金币?
思路:前缀和, z [ i ] z[i] z[i]:表示从1~i 需要的金币, f [ i ] f[i] f[i]:表示从n~i需要的金币数。

void solve()
{
	int n,m;
	cin>>n;

	for(int i=1; i<=n; i++)		cin>>a[i];
	
	f[n-1] = 1;
	for(int i=n-1; i>=2; i--)
	{
		if(a[i]-a[i-1] < a[i+1]-a[i])	f[i-1] = 1;
		else	f[i-1] = a[i]-a[i-1];
	}
	for(int i=n; i; i--)		f[i] += f[i+1];

	z[2] = 1;
	for(int i=2; i<=n-1; i++)
	{
		if(a[i+1]-a[i] < a[i]-a[i-1])	z[i+1]=1;
		else	z[i+1] = a[i+1]-a[i]; 
	}

	for(int i=1; i<=n; i++)		z[i] += z[i-1];

	cin>>m;

	while(m--)
	{
		int x,y;	cin>>x>>y;
		if(x>=y)
			cout << f[y] - f[x] << '\n';
		else
			cout << z[y] - z[x] << '\n'; 
	}

}
d

题意:从左往右 n n n个怪物,每个怪物都有攻击力和防御力,每轮每个怪物都会对两边的怪物进行攻击,如果怪物承受的伤害高于他的防御力,那么这个怪物就阵亡了,每轮结束后,会阵亡多少怪物?
思路:分情况讨论

  • 当一轮没有怪物阵亡,那么,以后都不会有怪物阵亡。
  • 当怪物阵亡,只会影响到它两边的怪物,那么这个怪物两边的怪物将下一轮会相互攻击,所以我们需要考虑阵亡怪物的两边。
    我们用v存储会对结果造成影响的活着怪物的位置,第一轮,所有的怪物都会对结果造成影响,用 l [ i ] l[i] l[i]:表示第 i i i 个怪左边的怪的位置,用 r [ i ] r[i] r[i]:表示第 i i i 个怪右边的怪的位置,每次死亡都要更新死亡怪两边怪的 l [ i ] l[i] l[i] r [ i ] r[i] r[i] v i s [ i ] vis[i] vis[i]:记录状态是否死亡。记录怪是否死亡是为了防止下面这种情况,如果进行状态的判断则会将已死亡的三号怪加入 v v v 中。
    在这里插入图片描述
void solve()
{
	int n;	cin>>n;

	vector<int> a(n+1),b(n+1);
	vector<int> l(n+2),r(n+2);


	for(int i=1; i<=n; i++)		cin>>a[i];
	for(int i=1; i<=n; i++)		cin>>b[i];
	for(int i=1; i<=n; i++)		l[i] = i-1 , r[i] = i+1;

	l[1]=-1,r[n]=-1;

	set<int> v;		//活着的
	set<int> die;	//死掉的
	vector<int> vis(n+1,0);	//标记状态

	for(int i=1; i<=n; i++)		v.insert(i);

	bool res = false;
	for(int i=1; i<=n; i++)
	{
		if(res)
		{
			cout << "0 ";
			continue;
		}
		for(auto it=v.begin(); it!=v.end(); it++)
		{
			int t = *it;
			int sum = 0;
			if(l[t]!=-1)	sum += a[l[t]];
			if(r[t]!=-1)	sum += a[r[t]];
			if(sum > b[t])	die.insert(t) , vis[t] = 1;
		}
		v.clear();

		for(auto it=die.begin(); it!=die.end(); it++)
		{
			int t = *it;
			if(l[t]!=-1)	//l[t]是他左边活着的
			{
				r[l[t]] = r[t] ;
				if(!vis[l[t]]) 	v.insert(l[t]);		//特判防止死的进去
			}
			if(r[t]!=-1)	
			{
				l[r[t]] = l[t] ;
				if(!vis[r[t]]) v.insert(r[t]);		//特判防止死的进去
			}
		}
		cout << die.size() << ' ';
		if(!die.size())		res = true;
		die.clear();
	}
	cout << '\n' ;
}
  • 15
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

离你很远的地方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值