2024.5.16晚训题解

临近比赛,晚训更加频繁了,希望同学们继续坚持下去!!!
来不及订正的话,至少要保证自己题目看了一遍,有所思考,把讲题思路理解理解。

A题 题解
确实是我刚开始学算法竞赛的时候第一次玩codeforces遇到的题目
想了快一小时 (当然现在读完题就秒了),苦于实现出来,讨论不清楚。所以说同学们,你能想到不代表你能自己写出来,一定要自己动手写。

实际上三个人的位置无外乎讨论进一步还是不动还是退一步
讨论不清楚就用枚举呗,直接三个循环枚举移动的量-1到1

#include<bits/stdc++.h>
using namespace std;
long long int ABS(long long int x,long long int y){
	if(x>y)return x-y;
	else return y-x;
}
long long int MIN(long long int x,long long int y){
	if(x>y)return y;
	else return x;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		//如果涉及到long long 取绝对值  max  min其实最好自己手写函数
		// if是最快的 
		long long int a,b,c;
		scanf("%lld%lld%lld",&a,&b,&c);
		long long int ans=1e18;
		for(int i=-1;i<=1;i++){
			for(int j=-1;j<=1;j++){
				for(int k=-1;k<=1;k++){
					ans=MIN(ans,ABS(a+i,b+j)+ABS(a+i,c+k)+ABS(b+j,c+k));
				}
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

B题chess960题解
经典模拟题了,按题目说的去实现程序即可
字符串找到两个 B B B的位置,判断这两个位置是否同奇偶,不同则符合
找到 K K K和两个 R R R 的位置 如果 K K K在两个 R R R中间则符合
两条都符合输出 Y e s Yes Yes否则输出 N o No No

#include<bits/stdc++.h>
using namespace std;
char str[100];
int b,l,r,m;
int main(){
    scanf("%s",str);
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(str[i]=='B')b+=(i+1);
        if(str[i]=='R'&&l)r=i+1;
        if(str[i]=='R'&&!l)l=i+1;
        if(str[i]=='K')m=i+1;
    }
    if(b&1&&r>m&&l<m)printf("Yes");
    else printf("No");
}

C题PC on the Table 题解
找到连着的两个T,把他俩变成PC,要求变得尽可能得多,那肯定从左往右碰到俩就变俩,这样能变出来最多的

#include<bits/stdc++.h>
using namespace std;
char str[105][105];
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",str[i]+1);
		for(int j=1;j<=m;j++){
            if(str[i][j]=='T'&&str[i][j-1]=='T'){
                str[i][j]='C',str[i][j-1]='P';
            }
        }
        printf("%s",str[i]+1);
        printf("\n");
    }
}

D题Count Subtractions 题解
这其实数学里面的辗转相除法
完全可以用递归来解决
自动的计算 ,设置好return 条件

#include<bits/stdc++.h>
using namespace std;
long long  n,m;
long long dfs(long long a, long long b){
    if(a==b)return 0;
    if(!b)return -1;
    return a/b+dfs(b,a%b);
}
int main(){
    scanf("%lld%lld",&n,&m);
    printf("%lld",dfs(n,m));
    return 0;
}

E题题解
非常非常板子的知识点运用,优先对列以及set
N道菜,各有各的价值,并且相同价值的组合只算一种,很明显我们需要去重。哪种组合是第K小的呢???

考虑初始状态啥也不取,那么价值就是0
我们每种组合都可以考虑分步来组合
即每一步无外乎是再买一道 i = 1 到 N i=1到N i=1N其中一个菜
考虑前一个状态的最小值组合,例如是第 M 小的组合 M小的组合 M小的组合,在此基础上再去取一道菜,一定能找到第 M + 1 M+1 M+1小的组合,下一轮循环以此类推,这个快速维护最小值,以及去重操作,其实就是优先队列+set的操作
对于已经存在的组合我们是直接忽略掉的。
每轮拿出最小值后要从优先队列弹出,本轮处理好了以后其实top就是当前最小值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll now,n,m,a[500];
priority_queue<ll, vector<ll>, greater<ll> > q;
set<ll> s;
int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    q.push(0);s.insert(0);
    for(int j=1;j<=m;j++){
        now=q.top();q.pop();
        for(int i=1;i<=n;i++){
            if(s.find(now+a[i])==s.end())q.push(now+a[i]),s.insert(now+a[i]);
        }
    }
    printf("%lld",q.top());
    return 0;
}

或许代码看着短,但是思维是需要你好好思考的
我们的优先队列里面存的元素,其实是会内部排序,top一定是最小的,拿出最小的以后又会调整,始终保证我们放进多种组合价值后top还是当前最小值。你可以想象类似于BFS,起始状态是0,每次搜索N个菜拿走,每次从最小的价值组合继续搜索,因此第M次一定是第M小的组合

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值