Codeforces Global Round 17 A-C

菜鸟第一次打Global Round,之前虚拟的做了下16的,感觉前四道都很简单,没想到这次比16难那么多…
A. Anti Light’s Cell Guessing
给出n*m的网格线,其中隐藏了一个坐标,每给计算机一个坐标,计算机会回馈你一个曼哈顿距离,即 |a1−a2|+|b1−b2|,输出在网格线中找出隐藏坐标所需最少的点的数量。
大坑题,麻了,我很快就想到如果行和列有1的话1个坐标就够了,其余情况都是2,结果就一直wr,我完美的越过了1 * 1这个特殊情况。在接下来的一个小时中我重复着读题和举例,终于心态崩了,还好有同学一下子给我点醒了。1 * 1只有那么一个点,它就是隐藏坐标…

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int main()
{
    int n,i,j,t;
    cin>>t;
    while(t--)
    {
        cin>>i>>j;
        if(i==1&&j==1) {cout<<"0"<<endl;continue;}
        int ans=min(i,j);
        if(ans==1) cout<<"1"<<endl;
        else cout<<"2"<<endl;
    }
}

此时心态已经炸了,做个A题就用了七十多分钟(主要是我太笨了)还错了好几次,本来想上床睡觉算了,还是勉强坚持下来。
B. Kalindrome Array
给定一个序列,你可以选其中一个数x,序列中等于x的数你可以删1个,2个…也可以全删掉,x你可以任选。如果通过这样的操作你能将它变成回文串,那么输出YES,否则输出NO。
好家伙,个人认为这可比一般div2的B难多了,但是这道题让我觉得似曾相识(Codeforces Round #750 (Div. 2)-C Grandma Capa Knits a Scarf)
https://editor.csdn.net/md/?articleId=120962944
(这篇博客里废话有点多,可以直接往下划)
尽管两道题很相似,但是思路还是不太一样的。这道题要用到贪心+双指针。贪心用在我们选定x的时候,把等于x的全部删掉都不能成为回文串时,那它不管少删多少个,它都不可能是回文串,这样就简单多了。
然后我们用双指针,我分了两种情况,当a[l]!=a[r]时我们可以将l的值赋给x,也可以将r的值赋给x,如果这两种情况都不能形成回文串的话就可以输出NO了,如果有哪怕一种情况成立,那必然是YES。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int a[200001];
int b[200001];
int main()
{
    int n,i,t,l,r;
    cin>>t;
    while(t--)
    {
        int u=0,k,num=0;
        cin>>n;
        for(i=0;i<n;i++)
        {
            cin>>a[i];
        }
        l=0;r=n-1;
        while(1)
        {   if(r-l<=0) break;
            if(a[l]==a[r]) {l++;r--;continue;}
            else{
                if(u==0) {k=a[l];u=1;l++;continue;} //第一种情况,把l赋值给u
                if(a[l]==k) {l++;continue;}
                if(a[r]==k) {r--;continue;} //两个指针扫到等于u的数时直接跳过继续判断,这样等于删除
                if(a[l]!=k&&a[r]!=k) {num++;break;} //这样还出现不是回文串的情况那它就不可能是了
            }
        }
        l=0;r=n-1;
        u=0;
        while(1)
        {   if(r-l<=0) break;
            if(a[l]==a[r]) {l++;r--;continue;}
            else{
                if(u==0) {k=a[r];u=1;r--;continue;} //第二种情况,把r赋值给u
                if(a[r]==k) {r--;continue;} //同理
                if(a[l]==k) {l++;continue;}
                if(a[l]!=k&&a[r]!=k) {num++;break;}
            }
        }
        if(num==2) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
}

C. Keshi Is Throwing a Party
一个人想邀请它的朋友们来聚会,但是这些朋友很挑剔,从1-n的朋友们身上有1-n美元,给定a和b。a指这个人不希望到场的人中有多于a个人比他富裕,b指这个人不希望到场的人中有多于b个人比它贫穷,输出这个人最多能邀请多少个朋友。
是一道二分答案的题目,虽然我最近在练二分,但是这道题完全没有二分的思路(还是练的少了)。当时想用贪心排序做,但是后来发现好像不太行,就上床睡觉了…
其实也并没有那么难,二分答案的题目只要写出check函数,然后合理修改二分模板就行了。重点在check函数上:对于一个人来说,到场的人不能有太多比它富裕的,也不能有太多比它贫穷的,这题刚好每个人的美元已经按递增顺序排好了,在check函数里可以直接遍历。贫穷的好办,在我们遍历到一个人时,之前邀请了多少个人p已经记录了下来,只要b[i]>=p就可以满足了;富裕比较麻烦些,但是我们要判断的x人已经由二分给了check函数,那么比这个人富裕的人数就是x-p-1(别忘了减它自己),那么满足a[i]>=x-p-1就行了,同时满足这两个条件我们就可以邀请它,然后继续遍历。如果最后邀请的人p大于等于x,说明二分给出的邀请人数x小了,要把它变大,反之就把它变小,这样写二分就可以了。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int a[200001];
int b[200001];
int i,n;
bool judge(int x)
{
    int p=0;
    for(i=0;i<n;i++)
    {
        if(a[i]>=x-p-1&&b[i]>=p)  p++; //满足富裕和贫穷两个条件才可以邀请他
    }
    if(p>=x) return true;
    else return false;
}
int main()
{
    int t,ans,mid;
    cin>>t;
    while(t--)
    {   ans=0;
        cin>>n;
        for(i=0;i<n;i++)
        {
            cin>>a[i]>>b[i];
        }
        int l=0,r=n;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(judge(mid))
            {
                l=mid+1;
                ans=max(ans,mid); //我们要求出能邀请的最大人数
            }
            else r=mid-1;
        }
        cout<<ans<<endl;
    }
}

D好像要根据题意来推,我是看不懂了…(懒)

上一篇:Codeforces Global Round 17


下一篇:Educational Codeforces Round 117