Educational Codeforces Round 124 (Rated for Div. 2) A-D
A
https://codeforces.com/contest/1651/problem/A
思路
第一轮一定是连续的两个数\(2i-1\),\(2i\)比赛,他们相加是奇数,必然是较小的奇数胜出。现在我们有\(1,3,5...2^{n}-1\)
之后的每一轮比赛一定是两个奇数比赛,他们相加是奇数,必然是大的数胜出。最后的winner是\(2^{n}-1\)
一个超级坑的地方(也可能是我太菜了呜呜呜):
不能直接用\(pow(2,n)\)输出答案!!,因为当结果较大时会自动输出浮点数的形式
否则你会get this而且还会开始怀疑思路出错

code
#define ll long long
using namespace std;
const int N = 100005;
ll n,m,t;
int main(){
cin>>t;
while(t--){
cin>>n;
// cout<<(pow(2,n)-1)<<endl;
ll ans=1;
for(int i=1;i<=n;i++)ans*=2;
ans-=1;
cout<<ans<<endl;
}
return 0;
}
B
https://codeforces.com/contest/1651/problem/B
思路
如果要prove him wrong,那么我们要找到满足\(2\vert a_{i}-a_{j}\vert \geq a_{i}+a_{j}\)的\(a_{i}\)和\(a_{j}\)的关系
不妨设\(a_{i}\geq a_{j}\),于是推出\(a_{i}\geq 3a_{j}\)
注意到题目的要求是\(10^{9}\geq a_{i} \geq 1\),满足上述关系的最长的数列为\(3^{0},3^{1},...3^{18}\),所以n的最大值为19
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
ll n,m,t;
int main(){
// cout<<pow(3,18);
cin>>t;
while(t--){
cin>>n;
if(n>19){
puts("NO");
continue;
}
puts("YES");
ll ans=1;
for(int i=1;i<=n;i++){
cout<<ans<<" ";
ans*=3;
}puts("");
}
return 0;
}
C
https://codeforces.com/contest/1651/problem/C
思路
容易发现,必须要满足所有点都位于环内,这样才可满足题目要求。
进一步得出\(a_{1},a_{n},b_{1},b_{n}\)必须和另一排的点相连,而为了最小化cost,每个角上的点应该要连另一排上耗费最小的点,这可以通过for循环一遍得到
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200005;
int n,m,t;
ll a[N],b[N];
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
ll ans=abs(a[1]-b[1])+abs(a[n]-b[n]);
ans=min(ans,abs(a[1]-b[n])+abs(a[n]-b[1]));
ll a1=1e18,an=1e18,b1=1e18,bn=1e18;
for(int i=1;i<=n;i++){
a1=min(a1,abs(a[1]-b[i]));
an=min(an,abs(a[n]-b[i]));
b1=min(b1,abs(b[1]-a[i]));
bn=min(bn,abs(b[n]-a[i]));
}
ans=min(ans,a1+an+b1+bn);
//a1b1
ans=min(ans,an+bn+abs(a[1]-b[1]));
//a1bn
ans=min(ans,an+b1+abs(a[1]-b[n]));
//anb1
ans=min(ans,a1+bn+abs(a[n]-b[1]));
//anbn
ans=min(ans,a1+b1+abs(a[n]-b[n]));
cout<<ans<<endl;
}
return 0;
}
D
https://codeforces.com/contest/1651/problem/D
思路
先考虑:怎么样能找到距离最近的点呢?
因为题目的点的范围有点大,最开始想到了二分答案。但是写起来逐渐发现不太对 可能是我水平太差了
其实更直观的想法当然是bfs!如果从已知点出发,走到了未知点,那么未知点的答案就可以根据已知点更新。
具体一点的思路是:先判断和当前点曼哈顿距离=1的点是否都已出现,如果不是就将当前点的dis值设为1,同时记录答案位置;做完上一步之后把他们加进队列,开始bfs更新答案
code
#include<bits/stdc++.h> ///idea
#define ll long long
using namespace std;
const int N = 200005;
int n,m,t;
struct node{
int x;
int y;
}a[N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
map<pair<int,int>,int>mp;
map<int,pair<int,int>>ans;
int dis[N];
struct node2{
int id;
int d;
};
queue<node2>q;
void bfs(){
while(!q.empty()){
node2 now=q.front();
q.pop();
for(int i=0;i<4;i++){
int x=a[now.id].x+dir[i][0];
int y=a[now.id].y+dir[i][1];
int id=mp[make_pair(x,y)];
if(id){
if(dis[id]>dis[now.id]+1){
dis[id]=dis[now.id]+1;
ans[id]=ans[now.id];
q.push({id,dis[id]});
}
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
mp[make_pair(a[i].x,a[i].y)]=i;
dis[i]=1e9;
}
//处理所有直接可达的
for(int i=1;i<=n;i++){
bool f=0;
for(int j=0;j<4;j++){
int x=a[i].x+dir[j][0];
int y=a[i].y+dir[j][1];
if(!mp[make_pair(x,y)]){
f=1;
ans[i]=make_pair(x,y);
dis[i]=1;
break;
}
}
}
//不能直接抵达的
for(int i=1;i<=n;i++){
if(dis[i]==1){
q.push({i,1});
}
}
bfs();
//print
for(int i=1;i<=n;i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
system("pause");
return 0;
}
总结
不知道昨晚怎么回事。。A-C题一共wa6发。。。A也能wa2发我是没想到的😅前3题过了多少人我的排名就是多少。。。。
真就不wa两发不过签到呗
可能还是cf打的少了,打比赛的感觉不对,要继续注意细节+多vp+多写cf C、D题
不过昨晚是第一次用vsc打cf(试图归咎于外因(划掉

浙公网安备 33010602011771号