Codeforces Round #700 (Div. 2)

本文探讨了多场字符串操作游戏(如YetAnotherStringGame)的策略,以及英雄与怪兽的战斗策略(TheGreatHero)。通过模拟与贪心算法解决,涉及字符替换、攻击与防御计算。另一篇关于寻找局部最小值的问题(SearchingLocalMinimum)则展示了交互式问题的解决方案。最后两篇关于绘画数组的题目(PaintingtheArrayI,II)涉及序列优化与最小值求解,利用贪心和动态规划技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A:Yet Another String Game

  题目大意是Alice和Bob轮流对一个字符串进行操作,每轮他俩都必须选择一个字符并对其作出修改。Alice的目标是让这个字符串的字典序尽可能小,Bob的目标是让这个字符串的字典序尽可能大,问双方操作后的新字符串是什么。
  按顺序模拟,注意考虑字符本身是’a’和’z’的情况即可。

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
int main()
{
	close;int T;cin>>T;
	while(T--)
	{
		string s;cin>>s;
		for(int i=0;i<s.length();++i)
		{
			if(i&1){if(s[i]=='z') s[i]='y';else s[i]='z';}
			else{if(s[i]=='a') s[i]='b';else s[i]='a';}
		}
		cout<<s<<endl;
	}
}

B:The Great Hero

  题目大意是英雄和一群怪兽都有一个初始的攻击值和生命值,可以对同一个怪兽发动多次攻击,如果所有的怪兽死亡(哪怕英雄也在最后一轮战斗中死去)就输出“YES”,否则输出“NO”。
  延续了B题不坑你几发罚时就誓不为人的风格 。首先要对怪兽按照攻击值从小到大排序,因为可能有b[i]%A!=0b[i]\%A!=0b[i]%A!=0,英雄就需要多打一次,也就给自身多造成了a[i]a[i]a[i]点的伤害。先处理小的目的是为了实现英雄血量不够的情况下还能发动最后一次攻击然后和最后一只怪兽一起死亡的现象
在这里插入图片描述

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int maxn=1e5+100;
typedef long long ll;
struct Monsters{
	ll a,b,res;
	bool operator < (const Monsters&mon) const{return a<mon.a;}
}m[maxn];
int main()
{
	close;int T;cin>>T;
	while(T--)
	{
		ll A,B,n;cin>>A>>B>>n;
		for(int i=1;i<=n;++i) cin>>m[i].a;
		for(int i=1;i<=n;++i) cin>>m[i].b;
		int pos;sort(m+1,m+n+1);
		for(int i=1;i<=n;++i)
		{
			pos=i;
			ll h=(B/m[i].a)+(B%m[i].a!=0?1:0),l=(m[i].b/A)+(m[i].b%A!=0?1:0),r=min(h,l);
			B-=m[i].a*r;m[i].b-=A*r;
			if(B<=0) break;
		}
		if(pos<n) cout<<"NO\n";
		else if(pos==n){
			if(m[n].b<=0) cout<<"YES\n";
			else cout<<"NO\n";
		}
	}
}

C:Searching Local Minimum

  这是一道交互式问题,题目大意是只给定一个nnn(告诉你原序列是一个1~n的全排列中的一种),然后你的程序不断询问某个下标的值(最多不能超过100次询问),最后给出一个下标,满足ai<min(ai−1,ai+1)a_i<min(a_{i-1},a_{i+1})ai<min(ai1,ai+1)
  二分三分都是可以的,我这里采用的是三分法,虽然整个图像并不是一个完全的单峰函数,但题目也没要求输出全局最小值,因此通过三分法一定能够找到一个局部的单峰性质,也就能输出最小值。使用三分法需要严格注意自己输出的下标的值是否合法,最后的值是否正确(可能会因为写法不同造成偏移)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int main()
{
	int n;cin>>n;
	int l=0,r=n+1,x1,x2;
	while(l+1<r){
		int mid=(l+r)/2;
		cout<<"? "<<mid<<endl;fflush(stdout);
		cin>>x1;
		int midd=(mid+r)/2;
		cout<<"? "<<midd<<endl;fflush(stdout);
		cin>>x2;
		if(x1<x2) r=midd;
		else l=mid;
	}
	cout<<"! "<<l<<endl;fflush(stdout);
}

D1:Painting the Array I

  题目大意是定义了一种运算segsegseg,代表将一个序列中连续相同的一段仅保留其中一个后,新序列的元素个数。然后给定你一个原序列A,你需要找到一个子序列a0a^0a0a1=A−a0a^1=A-a^0a1=Aa0,问max{seg(a0)+(a1)}max\{seg(a^0)+(a^1)\}max{seg(a0)+(a1)}.
  贪心了一个小时都没贪出来的菜狗,而且这种前面的选择会影响后续的我断然不敢往贪心上面猜,但这个世界就是这么的奇妙
  使用贪心的策略,我们令last1,last2last1,last2last1,last2分别代表前两个序列的最后一个字符,现在来考虑第iii个字符:①last1==last2last1==last2last1==last2时,s[i]s[i]s[i]放在哪个序列后面都无所谓;②last1==s[i] && last2≠s[i]last1==s[i]\ \&\& \ last2\ne s[i]last1==s[i] && last2=s[i]时,直接放在序列2后就能得到最优解;③last2==s[i] && last1≠s[i]last2==s[i]\ \&\& \ last1\ne s[i]last2==s[i] && last1=s[i]时,直接放在序列1后就能得到最优解;④last1≠s[i] && last2≠s[i]last1\ne s[i]\ \&\& \ last2\ne s[i]last1=s[i] && last2=s[i]时,定义next[x]next[x]next[x]表示xxx在第iii个元素后的下一个出现位置,比较next[last1]next[last1]next[last1]next[last2]next[last2]next[last2],谁小放在谁后。

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int maxn=1e5+100;
int a[maxn],ind[maxn];
vector<int> v[maxn];
int main()
{
	close;int n;cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i],v[a[i]].push_back(i);
	int last1=0,last2=0,ans=0;
	for(int i=1;i<=n;++i)
	{
		ind[a[i]]++;
		if(last1==last2){
			if(last1!=a[i]) last1=a[i],ans++;
		}
		else if(last1==a[i] && last2!=a[i]) last2=a[i],ans++;
		else if(last2==a[i] && last1!=a[i]) last1=a[i],ans++;
		else{
			ans++;
			int next1=n+1,next2=n+1;
			if(ind[last1]<v[last1].size()) next1=v[last1][ind[last1]];
			if(ind[last2]<v[last2].size()) next2=v[last2][ind[last2]];
			if(next1<next2) last1=a[i];
			else last2=a[i];
		}
	}
	cout<<ans;
}

D2:Painting the Array II

  题目大意和上述题目相同,仅仅是询问min{seg(a0)+(a1)}min\{seg(a^0)+(a^1)\}min{seg(a0)+(a1)}.
  使用贪心的策略,我们令last1,last2last1,last2last1,last2分别代表前两个序列的最后一个字符,现在来考虑第iii个字符:①last1==last2last1==last2last1==last2时,s[i]s[i]s[i]放在哪个序列后面都无所谓;②last1==s[i] && last2≠s[i]last1==s[i]\ \&\& \ last2\ne s[i]last1==s[i] && last2=s[i]时,直接放在序列1后就能得到最优解;③last2==s[i] && last1≠s[i]last2==s[i]\ \&\& \ last1\ne s[i]last2==s[i] && last1=s[i]时,直接放在序列2后就能得到最优解;④last1≠s[i] && last2≠s[i]last1\ne s[i]\ \&\& \ last2\ne s[i]last1=s[i] && last2=s[i]时,定义next[x]next[x]next[x]表示xxx在第iii个元素后的下一个出现位置,比较next[last1]next[last1]next[last1]next[last2]next[last2]next[last2],谁小放在另一个后。

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int maxn=1e5+100;
int a[maxn],ind[maxn];
vector<int> v[maxn];
int main()
{
	close;int n;cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i],v[a[i]].push_back(i);
	int last1=0,last2=0,ans=0;
	for(int i=1;i<=n;++i)
	{
		ind[a[i]]++;
		if(last1==last2){
			if(last1!=a[i]) last1=a[i],ans++;
		}
		else if(last1==a[i] && last2!=a[i]) continue;
		else if(last2==a[i] && last1!=a[i]) continue;
		else{
			ans++;
			int next1=n+1,next2=n+1;
			if(ind[last1]<v[last1].size()) next1=v[last1][ind[last1]];
			if(ind[last2]<v[last2].size()) next2=v[last2][ind[last2]];
			if(next1<next2) last2=a[i];
			else last1=a[i];
		}
	}
	cout<<ans;
}

E:Continuous City

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值