临近比赛,晚训更加频繁了,希望同学们继续坚持下去!!!
来不及订正的话,至少要保证自己题目看了一遍,有所思考,把讲题思路理解理解。
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=1到N其中一个菜
考虑前一个状态的最小值组合,例如是第
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小的组合