【题解】CF3 合集

前言:

  1. 本人不会 LaTeX……请见谅
  2. 码风奇特,不喜勿喷哈
  3. 题面翻译取自 luogu,本蒟蒻也会安置原题链接
  4. 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
  5. AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
  6. 有写错的地方欢迎各位神犇指正
  7. 本套题共 4 道,预计阅读 + 理解时间小于 1h

正片开始!

CF3A

题面(可从下方链接跳转看原题题面):

国王独自一人在国际象棋棋盘上。尽管他很孤独,但他并不会灰心,因为他有国家大事要做。例如,他必须对方格 t 进行访问。因为国王没有浪费时间的习惯,所以他想从目前的位置(方格 s)上出发,走最少的步数。请你帮他做这件事。在一次移动中,国王可以到达与他目前所在方格有共同的边或共同的顶点的方格里(通常情况下,他可以移动到 8 个不同的方格里)

题目传送门

序言 & 结论:

难度:橙题

直接做就……(请自行脑补)

前置知识:切比雪夫距离

推理过程:

  • 国王的移动这是一个八连通
  • 走到目标位置所需的步数一定是横纵坐标的最小值——即切比雪夫距离
  • 考虑构造一条路径
  • 对于任意的两个坐标,我们可以对一种可行方案分成两个部分
  • 斜着走;直着走
  • 然后就判断方向即可
  • 撒花!

细节处理:

代码:

可以口胡这个题,代码没有任何难度捏

点击查看代码
#include<iostream>
#include<cstdio>
#include<cmath> 
using namespace std;
char s1[3],s2[3];
int main(){
    int x,y;
    char cx,cy;
    scanf("%s%s",s1,s2);
    x=s1[0]-s2[0];
    y=s1[1]-s2[1];
    cx=x<0?'R':'L';
    cy=y<0?'U':'D';
    x=abs(x);
    y=abs(y);
    printf("%d\n",x>y?x:y);
    while(x||y){
    	if(x){
    		x--;
    		printf("%c",cx);
		}
		if(y){
			y--;
			printf("%c",cy);
		}
		printf("\n");
	}
    return 0;
}

----------------------不 ~ 开 ~ 心 ~ 的分割线----------------------

CF3B

题面(可从下方链接跳转看原题题面):

给定整数 n,v

有一辆载重量为 v 的货车,准备运送两种物品。物品 A 的重量为 1,物体 B 的重量为 2,每个物品都有一个价值 pi
求货车可以运送的物品的最大价值

题目传送门

序言 & 结论:

难度:绿题

为什么本蒟蒻认为 CF3B 比 CF3C 更难捏(似乎 CF3C 也的确是个黄题)

相信在场的大巨就直接秒了一眼背包(咳咳,包寄的)

回归贪心~

推理过程:

  • 由题意,物品分为两类,重量为 1/2
  • 第一个贪心结论:同类物品选价值较高者必定更优
  • 这样,可以想到分类之后排序(降序)
  • 考虑到最后要输出物体编号,可用 pair(或结构体)同时记录价值 p[i] 和编号 i
  • 那么同类别我们处理完毕,可以考虑跨类别……
  • 这里会出现两种做法:
    1. 将重量为 1 的那一组两两合并(最大+次大,三大+四大),并与重量为 2 的那一组一块插入一个大根堆中
    2. 也是我写的,直接枚举选取重量 1 一组的个数 i,则重量 2 一组的个数为 (v-i)/2,每次求区间和可以用前缀和优化
  • 时间复杂度都是 O(nlogn),可以通过捏!

细节处理:

  • 输出的是编号哈!
  • 不论是 pair 还是结构体,cmp 函数都是必须的(重载运算符当我没说)
  • 建议使用稍快的输入输出方式(关同步流,快读快写,scanf+printf 都是不错的选择),数据量不是很小呢

代码:

背包也是不错的,但是蒟蒻不想 TLE,没有写背包的代码呢!

贪心代码如下:

点击查看代码
#include<iostream>
#include<algorithm>
#include<utility>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int maxn=1e5+10;
pii a[maxn],b[maxn];
int tot1,tot2,s[maxn];
int ans,sum,maxi,maxj;
inline bool cmp(pii a,pii b){
	return a.fi>b.fi;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n,v;
	cin>>n>>v;
	for(int i=1;i<=n;i++){
		int op,x;
		cin>>op>>x;
		if(op==1){
			a[++tot1]=mp(x,i);
		}else{
			b[++tot2]=mp(x,i);
		}
	}
	sort(a+1,a+tot1+1,cmp);
	sort(b+1,b+tot2+1,cmp);
	for(int i=1;i<=tot2;i++){
		s[i]=s[i-1]+b[i].fi;
	}
	for(int i=0;i<=tot1&&i<=v;i++){
		int j=min((v-i)>>1,tot2);
		sum+=a[i].fi;
		if(sum+s[j]>ans){
			ans=sum+s[j];
			maxi=i;
			maxj=j;
		}
	}
	cout<<ans<<endl;
	for(int i=1;i<=maxi;i++){
		cout<<a[i].se<<' ';
	}
	for(int i=1;i<=maxj;i++){
		cout<<b[i].se<<' ';
	}
	return 0;
}

----------------------不 ~ 开 ~ 心 ~ 的分割线----------------------

CF3C

题面(可从下方链接跳转看原题题面):

篇幅原因,中文题面不放在这里了——

题目传送门

序言 & 结论:

这 175 个测试点测得我的心惊肉跳的(不 ~ 开 ~ 心 ~)

难度:黄题

这种题总是没有难度的,毕竟数据量才 3×3,怎么搜都不会超时嘛!

规则怪谈:如果你在提交之后看到了血红色的 WA,请不要调试你的代码,立刻重构,不然……

推理过程:

  • 先判不合法
  • 三点连一线
  • 判断谁获胜
  • 无胜棋局续

细节处理:

  • 请注意!井字棋对角线连成三个也算获胜的哈
  • DFS 的终止条件千万不要面面俱到,不然你会 AC
  • 多说无益,详见代码!

代码:

切水题~ 切水题~ 我是切水题的小行家~

点击查看代码
#include<iostream>
using namespace std;
const int maxn=4;
char mp[maxn][maxn];
int cnt1,cnt2;
bool flag1,flag2;
inline void dfs(int a,int b,int x,int y,int tot,char c){
	if(tot==3){
		if(c=='X'){
			flag1=true;
		}else{
			flag2=1;
		}
		return;
	}else if(a+x<4&&a+x>0&&b+y<4&&b+y>0&&mp[a+x][b+y]==c){
		dfs(a,b,a+x,b+y,tot+1,c);
	}
	return;
}
int main(){
	for(int x=1;x<=3;x++){ 
		for(int y=1;y<=3;y++){
			cin>>mp[x][y];
			if(mp[x][y]=='X'){
				cnt1++;
			}
			if(mp[x][y]=='0'){
				cnt2++;
			}
		}
	}
	if(cnt2>cnt1||cnt1-cnt2>1){
		cout<<"illegal"<<endl;
		return 0;
	}
	for(int x=1;x<=3;x++){
		for(int y=1;y<=3;y++){
			if(mp[x][y]!='.'){
				for(int a=-1;a<2;a++){
					for(int b=-1;b<2;b++){
						if(a!=0||b!=0){
							dfs(a,b,x,y,1,mp[x][y]);
						}	
					}						
				}					
			}
		}			
	}
	if((flag1&&flag2)||(flag1&&cnt1==cnt2)||(flag2&&cnt1>cnt2)){
		cout<<"illegal"<<endl;
	}else if(flag1){
		cout<<"the first player won"<<endl;
	}else if(flag2){
		cout<<"the second player won"<<endl;
	}else if(cnt1+cnt2==9){
		cout<<"draw"<<endl;
	}else if(cnt1<=cnt2){
		cout<<"first"<<endl;
	}else{
		cout<<"second"<<endl;
	}
	return 0;
}

----------------------不 ~ 开 ~ 心 ~ 的分割线----------------------

CF3D

题面(可从下方链接跳转看原题题面):

给一个序列,序列里面会有左括号、问号、右括号。对于一个“?”而言,可以将其替换为一个“(”,也可以替换成一个“)”,但是都有相应的代价

问:如何替换使得代价最小。前提是替换之后的序列中,括号是匹配的。如果不能替换为一个括号匹配的序列则输出-1

题目传送门

序言 & 结论:

咿呀咿呀~(日常 WA 后抽风)

难度:蓝题

前置知识:优先队列

推理过程:

  • “?”让人很“?”
  • 所以考虑先把所有的“?”都替换成“)”
  • 接下来我们在这个括号序列上进行操作
  1. 合法性:
  • 先让相邻的“(”与“)”进行匹配
  • 如果序列首位为“)”或者末尾为“(”,不合法!
  • 如果“(”的数量大于“)”的数量加“?”的数量,直接宣布不合法,下班!
  • 一顿调整之后,“(”的数量不等于“)”的数量
  1. 最优性:
  • 在合法的情况系,我们进行将“?”处的“)”替换成“(”
  • 一次替换的代价是 a[i]-b[i]
  • 诶?这个代价只和 i 有关——可以贪心!
  • 我们可以预处理所有合法方案的 a[i]-b[i],直接插入优先队列中
  • 幸甚至哉,歌以咏志!

细节处理:

  • 贪心本身不难,就是合法性的判断非常考察细节
  • 不开祖宗见 long long
  • 使用 scanf 和 printf 的各位神犇看过来,在 CF 提交时输出长整型的变量 ans 需要使用 "%I64d"奇奇怪怪的
  • cin cout 地表最强(尤其是本题输入含字符串)

代码:

讲的很详细了,注释就不写了

点击查看代码
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<utility>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define int long long
using namespace std;
const int maxn=5e4+10;
int a[maxn],b[maxn];
string s,str;
priority_queue<pii> q;
signed main(){
	cin>>s;
	int len=0;
	int l=0,r=0;
	str=s;
	for(int i=0;i<s.length();i++){
		if(s[i]=='('){
			l++;
		}else if(s[i]==')'){
			r++;
		}
		if(s[i]=='?'){
			str[i]=')';
			cin>>a[i]>>b[i];
			len++;	
		}
	}
	if(s[0]==')'||s[s.length()-1]=='('){
		cout<<-1<<endl;
		return 0;
	}
	if(abs(l-r)>len){
		cout<<-1<<endl;
		return 0;
	}
	int ans=0;
	l=0;
	r=0;
	if(s[0]!='('){
		str[0]='(';
	}
	l++;
	for(int i=1;i<str.size();i++){
		if(s[i]=='?'){
			q.push(mp(b[i]-a[i],i));
		}
		if(str[i]=='('){
			l++;
		}
		if(str[i]==')'){
			r++;
		}
		if(r>l){
			pii k=q.top();
			q.pop();
			int x=k.se;
			r--;
			l++;
			str[x]='(';
		}
	}
	if(l!=r){
		cout<<-1<<endl;
		return 0;
	}
	if(str[0]!='('||str[str.length()-1]!=')'){
		cout<<-1<<endl;
		return 0;
	}
	for(int i=0;i<str.length();i++){
		if(s[i]=='?'){
			if(str[i]=='('){
				ans+=a[i];
			}
			if(str[i]==')'){
				ans+=b[i];
			}
		}
	}
	cout<<ans<<endl;
	cout<<str<<endl;
	return 0;
}

完结撒花!

posted @   sunxuhetai  阅读(180)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示