文章目录
Educational Codeforces Round 169 (Rated for Div. 2)
写在前面
手速场,半小时A出3道题,后面直接坐牢1个多小时······,D题看了半天,有思路却不会写,赛后看了一下大佬们的代码确实非常好,我自己是写不出来的,E题博弈论没怎么学,就不补了QVQ
A. Closest Point
思路
签到题 ,有2种情况:
- 当 n > 2 n>2 n>2 时,无论放哪都不满足题意
- 当 n < = 2 n<=2 n<=2 时,n为1 或者 这两个数不相邻,那就满足题意
题目说明是一条直线,那么数没有重复且都是升序的
code
int a[N];
void solve(){
int n;cin >> n;
for(int i=1;i<=n;++i){
cin >> a[i];
}
if(n>2) cout << "NO" << endl;
else{
if(n==1 || a[2]-a[1]!=1) cout << "YES" << endl;
else cout << "NO" << endl;
}
return ;
}
B. Game with Doors
思路
这题需要考虑4种情况:
- Alice和Bob没有相交的区域,那么只需要关闭一扇门即可
- Alice和Bob完全重合,那么这些门需要全部关闭,即 r − l r-l r−l
- Alice和Bob的左边界或者右边界有重合,(那么我们拿右边界重合为例,我们找出他们两左边界的最大值
- a n s = r − m a x ( l , L ) + 1 ans=r-max(l,L)+1 ans=r−max(l,L)+1 ,首先r到max(l,L)的门必须关闭,那么假设l<L,L到L-1和L Alice和Bob会有交界,这个门也需要关闭)
- Alice和Bob相交无重合, a n s = m i n ( r , R ) − m a x ( l , L ) + 2 ans=min(r,R)-max(l,L)+2 ans=min(r,R)−max(l,L)+2 ,重合的部分需要关闭且重合的边界也需要关闭
code
void solve(){
int a,b;
cin >> a >> b;
int l,r;
cin >> l >> r;
if(b<l || r<a){
cout << 1 << endl;
return ;
}
if(a==l && b==r){
cout << b-a << endl;
return ;
}
int k=max(a,l);
int s=min(b,r);
if(a==l || b==r){
cout << s-k+1 << endl;
return ;
}
else{
cout << s-k+2 << endl;
return ;
}
return ;
}
C. Splitting Items
思路
考点:贪心+模拟
由于Alice先手,那么每次Alice所拿的数>=Bob所拿的数
那么对于Bob来说,最优解自然是0
我们先将数进行升序排序,对于Bob来说,他需要操作的数都是偶数次的下标
对于这些数来说,让他们尽可能和上一个数相同即可
code
const int N=1e6+5;
int a[N];
bool cmp(int x,int y){
return x>y;
}
void solve(){
int n,k;
cin >> n >> k;
for(int i=1;i<=n;++i) cin >> a[i];
sort(a+1,a+1+n,cmp);
int sum1=0,sum2=0;
for(int i=2;i<=n;i+=2){
int s=a[i-1]-a[i];
if(k>=s){
a[i]+=s;
k-=s;
}
else{
a[i]+=k;
break;
}
}
for(int i=1;i<=n;++i){
if(i & 1) sum1+=a[i];
else sum2+=a[i];
}
cout << sum1-sum2 << endl;
return ;
}
D. Colored Portals
思路
考点:二分+贪心
首先,x移动到y有3种可能:
- x可以直接到y,他的成本就为y-x
- x到y之间有一个中转点,x可以先到中转点在到y,成本也为y-x
- 考虑贪心策略,假设中转点在x左侧或者y右侧,我们尽可能让这个中转点靠近x或者靠近y,这样他的成本最低
这时我们可以用二分去优化这个查找的范围,思路不难,难点在于代码的实现
接下来直接看代码吧~~
code
const int N=1e6+5;
string s[N];
void solve(){
map<string,vector<int>> m;
int n,q;
cin >> n >> q;
for(int i=1;i<=n;++i){
cin >> s[i];
m[s[i]].push_back(i);//将当前字符串的下标存进去
}
while(q--){
int x,y;
cin >> x >> y;
int ans=inf;
if(x>y) swap(x,y);//让x<y
for(auto i : s[x])
for(auto j : s[y]){
if(i==j){//x和y能直接到达
ans=y-x;
break;
}
string t="";
t+=i,t+=j;
if(t[0]>t[1]) swap(t[0],t[1]);//题目是按字典序的排序,小的在前面
auto mid=lower_bound(m[t].begin(),m[t].end(),x);
if(mid!=m[t].end() && (*mid)<=y) ans=y-x;//先判断中转点是否在中间
auto l=mid;
auto r=upper_bound(m[t].begin(),m[t].end(),y);//找y右边的中转点
if(l!=m[t].begin()){//判断m[t]是否为空,这时l指向的是m[t].end()或者第一个大于等于x的数
l--;
ans=min(ans,(x-*l)*2+(y-x));
}
if(r!=m[t].end()) ans=min(ans,(*r-y)*2+(y-x));
}
cout << (ans==inf?-1 : ans) << endl;
}
return ;
}