Educational Codeforces Round 76 (Rated for Div. 2) (A-F)题解

A.Two Rival Students

小的位置向左走,大的位置向右走直到走到最左或最右端或者x为0。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,x,a,b;
        scanf("%d%d%d%d",&n,&x,&a,&b);
        if(a>b)
        swap(a,b);
        while(x>0&&a>1)
            x--,a--;
        while(x>0&&b<n)
            x--,b++;
        printf("%d\n",b-a);
    }
    return 0;
}

B.Magic Stick

贪心,如果是x偶数就乘3/2,如果是奇数就减一,直到当前的数大于等于y,则可以得到y.如果操作的过程中x的值重复出现,则不能得到y.

#include <bits/stdc++.h>
using namespace std;
map<int,int>mp;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mp.clear();
        int a,b;
        scanf("%d%d",&a,&b);
        while(a<b)
        {
            if(a&1)
            a--;
            else
            a=a/2*3;
            if(mp[a])
            break;
            mp[a]=1;
        }
        if(a>=b)
        printf("YES\n");
        else
        printf("NO\n");
    }
    return 0;
}

C. Dominated Subarray

题目可以转化为求出现重复数字的最短区间,然后就是尺取裸题

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int n;
int cnt[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        int n;
        scanf("%d",&n);
        for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
        int l = 1;
        int r = 2;
        int ans=1e9;
        cnt[a[l]]=1;
        while(1)
        {
            while(r<=n)
            {
                if(!cnt[a[r]])
                cnt[a[r]]=1;
                else{
                    cnt[a[r]]++;
                    break;
                }
                r++;
            }
            if(r>n)
            break;
            while(cnt[a[l]]!=2){
                cnt[a[l]]--,l++;
            }
            cnt[a[l]]--;
            l++;
            r++;
            ans=min(ans,r-l+1);
        }
        if(ans!=1e9)
        printf("%d\n",ans);
        else
        printf("-1\n");
    }
    return 0;
}

D. Yet Another Monster Killing Problem

首先想到每一次应该选择可以杀最多怪物的英雄上。维护当天能杀大于等于c个怪物的英雄最强的战斗力,然后用ST表维护怪物战斗力的区间最大值,每次二分求当天能杀的怪物个数。好像做复杂了

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int bin[20];
int Log[maxn];
int mx[20][maxn];
int bit[maxn];
int n;
int a[maxn];
void update(int x,int id)
{
    while(id){
        bit[id]=max(bit[id],x);
        id-=id&-id;
    }
}
int query(int id)
{
    int ans=0;
    while(id<=n)
    {
        ans=max(ans,bit[id]);
        id+=id&-id;
    }
    return ans;
}
void ST(int n)
{
    for(int i=1;i<=n;i++)
        mx[0][i]=a[i];
    for(int i=1;i<=Log[n];i++)
        for(int j=1;j<=n;j++)
            if(j+bin[i]-1<=n)
                mx[i][j]=max(mx[i-1][j],mx[i-1][j+bin[i-1]]);
}
int query(int x,int y)
{
    int t=Log[y-x+1];
    return max(mx[t][x],mx[t][y-bin[t]+1]);
}
int main()
{
    int t;
    scanf("%d",&t);
    bin[0]=1;
    for(int i=1;i<20;i++)
        bin[i]=bin[i-1]*2;
    Log[0]=-1;
    for(int i=1;i<=200000;i++)
        Log[i]=Log[i/2]+1;
    while(t--)
    {
        int mmx=0;
        scanf("%d",&n);
        for(int i = 0;i <= n;++i)
        bit[i]=0;
        for(int i = 1;i <= n;++i)
        scanf("%d",&a[i]),mmx=max(mmx,a[i]);
        ST(n);
        int m;
        scanf("%d",&m);
        int mmx2=0;
        while(m--)
        {
            int x,c;
            scanf("%d%d",&x,&c);
            mmx2=max(mmx2,x);
            update(x,c);
        }
        if(mmx2<mmx)
        {
            printf("-1\n");
            continue;
        }
        int now = 1;
        int ans=0;
        bool ok=true;
        while(now<n)
        {
            int l = now+1,r = n;
            while(l<=r)
            {
                int mid=l+r>>1;
                int tmp=query(now,mid);
                int c = mid-now+1;
                int you=query(c);
                if(you>=tmp)
                l = mid+1;
                else
                r = mid-1;
            }
            int d = l-1;
            now = d+1;
            ans++;
        }
        if(now==n)
        ans++;
        printf("%d\n",ans);
    }
    return 0;
}

E. The Contest

比赛的时候没往DP去想,赛后看到题目标签才发现是一个挺显然的DP.dp[i][j]表示把i放在第j行时最小需要的操作步骤,先预处理出1-n的初始位置belong[i],转移方程:

dp[i][1]=dp[i-1][1]+(belong[i]!=1);
dp[i][2]=min(dp[i-1][1],dp[i-1][2])+(belong[i]!=2);
dp[i][3]=min(dp[i-1][1],min(dp[i-1][2],dp[i-1][3]))+(belong[i]!=3);
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int dp[maxn][4];
int a[maxn],b[maxn],c[maxn];
int belong[maxn];
int main()
{
    int n;
    int aa,bb,cc;
    scanf("%d%d%d",&aa,&bb,&cc);
    n=aa+bb+cc;
    for(int i = 1;i <= aa;++i)
        scanf("%d",&a[i]),belong[a[i]]=1;
    for(int i = 1;i <= bb;++i)
        scanf("%d",&b[i]),belong[b[i]]=2;
    for(int i = 1;i <= cc;++i)
        scanf("%d",&c[i]),belong[c[i]]=3;
    dp[1][1]=1;
    dp[1][2]=1;
    dp[1][3]=1;
    dp[1][belong[1]]=0;
    for(int i = 2;i <= n;++i)
    {
        dp[i][1]=dp[i-1][1]+(belong[i]!=1);
        dp[i][2]=min(dp[i-1][1],dp[i-1][2])+(belong[i]!=2);
        dp[i][3]=min(dp[i-1][1],min(dp[i-1][2],dp[i-1][3]))+(belong[i]!=3);
    }
    printf("%d\n",min(dp[n][1],min(dp[n][2],dp[n][3])));
    return 0;
}

F.Make Them Similar

先枚举x的前15位,用vector储存相邻两个数与x异或后的0的个数的差,再枚举后15位进行同样的操作,最后枚举前15位的差分数组,查询后15位里有没有与它相反的数组(这里可以用map)。

#include <bits/stdc++.h>
using namespace std;
int a[105];
vector<int>v[32770];
map<vector<int>,int>mp;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    int x = 0;
    int last;
    for(int i = 0;i < (1<<15);++i)
    {
        int tmp;
        for(int j = 1;j <= n;++j)
        {
            tmp = a[j]^i;
            int cnt=0;
            for(int k = 0;k < 15;++k)
                if((1<<k)&tmp)
                    cnt++;
            if(j==1)
            v[i].push_back(0);
            else
            v[i].push_back(cnt-last);
            last=cnt;
        }
    }    
    vector<int>t;
    for(int i = 0;i < 1<<15;++i)
    {
        int ii = i;
        ii<<=15;
        t.clear();
        int tmp;
        for(int j = 1;j <= n;++j)
        {
            tmp = a[j]^ii;
            int cnt=0;
            for(int k = 15;k < 30;++k)
                if((1<<k)&tmp)
                    cnt++;
            if(j==1)
            t.push_back(0);
            else
            t.push_back(cnt-last);
            last=cnt;
        }
        mp[t]=ii;
    }
    for(int i = 0;i < (1<<15);++i)
    {
        vector<int>p;
        for(int j = 0;j < v[i].size();++j)
        p.push_back(-v[i][j]);
        if(mp[p])
        {
            int ans=i+mp[p];
            printf("%d\n",ans);
            return 0;
        }
    }
    printf("-1\n");
    return 0;
}
posted @ 2019-11-16 18:10  tryatry  阅读(127)  评论(0编辑  收藏  举报