【题解】CF3 合集
前言:
- 本人不会 LaTeX……请见谅
- 码风奇特,不喜勿喷哈
- 题面翻译取自 luogu,本蒟蒻也会安置原题链接
- 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
- AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
- 有写错的地方欢迎各位神犇指正
- 本套题共 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 的那一组两两合并(最大+次大,三大+四大),并与重量为 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 后抽风)
难度:蓝题
前置知识:优先队列
推理过程:
- “?”让人很“?”
- 所以考虑先把所有的“?”都替换成“)”
- 接下来我们在这个括号序列上进行操作
- 合法性:
- 先让相邻的“(”与“)”进行匹配
- 如果序列首位为“)”或者末尾为“(”,不合法!
- 如果“(”的数量大于“)”的数量加“?”的数量,直接宣布不合法,下班!
- 一顿调整之后,“(”的数量不等于“)”的数量
- 最优性:
- 在合法的情况系,我们进行将“?”处的“)”替换成“(”
- 一次替换的代价是 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;
}
完结撒花!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具