Codeforces Round #687(Div2)A~D题题解

A. Prison Break

题目传送门:

A. Prison Break

题目大意:

有一个n*m的监狱,每一个格子有一个犯人,坐标为( r , c )的格子有一条逃生通道,犯人每一秒可以向相邻的一个格子移动,问所有犯人到达逃生通道最久需要多少秒。

思路:

判断监狱四个角上的犯人到达逃生通道的时间即可

AC Code

#include
using namespace std;
int main()
{
     
    int t;
    scanf("%d",&t);
    while(t--)
    {
     
        int n,m,r,c;
        scanf("%d%d%d%d",&n,&m,&r,&c);
        int res=0;
        res=max(res,abs(1-c)+abs(1-r));
        res=max(res,abs(n-r)+abs(m-c));
        res=max(res,abs(1-r)+abs(m-c));
        res=max(res,abs(n-r)+abs(1-c));
        printf("%d\n",res);
    }
    //system("pause");
    return 0;
}

B. Repainting Street

题目传送门:

B. Repainting Street

题目大意:

有n个房子,每个房子有自己初始颜色ci。画家每次可以画连续的k个房子,可以画成任意颜色,或者不变。问最少画几次可以使所有的房子都变成一样的颜色。

思路:

我们首先看题目的数据范围,初始颜色最多只有100种,房屋最多有1e5。所以我们枚举每种颜色,进行操作然后取小即可。

AC Code

#include
using namespace std;
const int N=1e5+10;
int c[N],ans[105];
int main()
{
     
    int t;
    scanf("%d",&t);
    while(t--)
    {
     
        int n,k;
        scanf("%d%d",&n,&k);
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++)
        {
     
            scanf("%d",&c[i]);
            ans[c[i]]=1;
        }
        int maxn=0x3f3f3f3f;
        for(int i=1;i<=100;i++)
        {
     
            if(ans[i]==0) continue;
            int p=0,num=0;
            int idx=1;
            while(idx<=n)
            {
     
                num=0;
                while(c[idx]!=i&&idx<=n)
                {
     
                    num++;
                    idx++;
                }
                if(num>0) 
                {
     
                    p+=num/k;
                    if(num%k) 
                    {
     
                        p++;
                        idx=idx+k-num%k;
                    }
                }
                while(c[idx]==i&&idx<=n) idx++;
            }
            maxn=min(maxn,p);
        }
        printf("%d\n",maxn);
    }
    //system("pause");
    return 0;
}

C. Bouncing Ball

题目传送门:

C. Bouncing Ball

题目大意:

有n个单元格,有一个小球会从左边来,第一次会落在单元格p,然后会落在单元格p+k,然后会落在p+2k……直到弹出第n个单元格为止。只有当当前位置的单元格有平台时,小球才能继续往下弹。你有两个操作:
1、花费x秒的时间在任意单元格添加一个平台。
2、花费y秒的时间删去最前面的单元格。
问最少需要多少秒,可以使小球弹出第n个单元格。

思路:

我们发现,如果从前往后枚举p点所在的位置,然后从该点开始一步一步往下跳进行模拟,那么肯定会超时。然后我们观察到很重要的一个特征是从第一次之后,接下去每次跳的距离都为k。最后一步的落点一定在n-k+1~n之间,那么从后往前推导即可,有点动态规划和后缀和的意思。

AC Code

#include
using namespace std;
const int N=1e5+10;
typedef long long LL;
LL a[N],f[N*2];
int main()
{
     
    int t;
    scanf("%d",&t);
    while(t--)
    {
     
        int n,p,k;
        scanf("%d%d%d",&n,&p,&k);
        for(int i=1;i<=n;i++)
            scanf("%1d",&a[i]);
        int x,y;
        scanf("%d%d",&x,&y);
        memset(f,0,sizeof(f));
        for(int i=n;i>=1;i--)
        {
     
            if(a[i]==0)
            {
        
                if(i+k<=n) f[i]=f[i+k]+1;
                else f[i]=1;
            }
            else f[i]=f[i+k];
        }
        LL minn=0x3f3f3f3f;
        for(int i=n;i>=1;i--)
        {
     
            if(i-p<0) break;
            LL num=f[i]*x+(i-p)*y;
            minn=min(minn,num);
        }
        printf("%lld\n",minn);
    }
    //system("pause");
    return 0;
}

D. XOR-gun

题目传送门:

D. XOR-gun

题目大意:

给你一个长度为n的单调不降序列a,每次操作可以取出相邻的两个数,异或后插入原来的位置,问最少操作几次才能使该数列不是单调不降序列。

思路:

我们从位运算的角度考虑,如果有三个连续的数的最高位相同,那么后面两个数的异或结果一定要比第一个数小。(比赛的时候咋没想到呢QAQ)。而数据范围是1e5<2^30。所以当n>60时,一定会存在连续的三个数的最高位相同,那么直接输出1即可。对于小于60的情况,我们可以暴力枚举合并的左区间和右区间,时间复杂度为60 ^ 3 ,是完全可行的。

AC Code

#include
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
     
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
     
        int x;
        scanf("%d",&x);
        a[i]=a[i-1]^x;
    }
    if(n>60) printf("1\n");
    else
    {
     
        int maxn=1e9;
        for(int l=1;l<n-1;l++)
        {
     
            for(int mid=l;mid<n;mid++)
            {
     
                for(int r=mid+1;r<=n;r++)
                {
     
                    if((a[mid]^a[l-1])>(a[r]^a[mid]))
                        maxn=min(maxn,mid-l+r-mid-1);
                }
            }
        }
        if(maxn==1e9) printf("-1\n");
        else printf("%d\n",maxn);
    }
    //system("pause");
    return 0;
}

这道题让我学到了连续几个数的异或结果该怎么求。
当做到二进制异或的题目没有头绪的时候,还是应该多从二进制的一些特征入手。

你可能感兴趣的:(Codeforces)