• CF1132.Educational Codeforces Round 61(简单题解)


    A .Regular Bracket Sequence

    题意:给定“((” , “()” ,  “)(”,  “))”四种,问是否可以组成合法括号匹配

    思路:设四种是ABCD,B可以不用管,而C在A或者D存在时可以不考虑,然后就是A=D。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    ll A,B,C,D,ans;
    int main()
    {
        scanf("%lld%lld%lld%lld",&A,&B,&C,&D);
        ans=B;
        if(A||D) ans+=C; ans+=2LL*min(A,D);
        if(ans==A+B+C+D) puts("1");
        else puts("0");
        return 0;
    }

    B .Discounts

    题意:给定N个物品,Q次询问,每次询问给定P,表示你可以选P个,最便宜的那个不用付款,问最少付款额。

    思路:排序,贪心。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,w,v) for(int i=w;i<=v;i++)
    using namespace std;
    const int maxn=2000010;
    ll a[maxn],sum,ans;
    int main()
    {
        int N,M,x; scanf("%d",&N);
        rep(i,1,N) scanf("%lld",&a[i]),sum+=a[i];
        sort(a+1,a+N+1);
        scanf("%d",&M);
        rep(i,1,M) {
            scanf("%d",&x);
            printf("%lld ",sum-a[N+1-x]);
        }
        return 0;
    }

    C .Painting the Fence

    题意:给定长度为N个点,M条线段,问选择M-2条,最多可以覆盖多少个点(N,M<5000)

    思路:首先如果点被覆盖数大于2,不用考虑了,一定被覆盖。所以先求出被1个线段覆盖的,被2覆盖的,然后枚举不选的线段,前缀和更新答案即可。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,w,v) for(int i=w;i<=v;i++)
    using namespace std;
    const int maxn=5100;
    int sum[maxn],num[3][maxn],ans,tot; pair<int,int>s[maxn];
    int main()
    {
        int N,M;
        scanf("%d%d",&N,&M);
        rep(i,1,M){
            scanf("%d%d",&s[i].first,&s[i].second);
            sum[s[i].first]++; sum[s[i].second+1]--;
        }
        rep(i,1,N) sum[i]+=sum[i-1];
        rep(i,1,N){
            if(sum[i]) tot++;
            num[1][i]+=num[1][i-1];
            num[2][i]+=num[2][i-1];
            if(sum[i]==1) num[1][i]++;
            if(sum[i]==2) num[2][i]++;
        }
        sort(s+1,s+M+1);
        rep(i,1,M)
         rep(j,i+1,M){
            if(s[j].first>s[i].second) ans=max(ans,tot-(num[1][s[i].second]-num[1][s[i].first-1])-(num[1][s[j].second]-num[1][s[j].
    first-1])); else if(s[j].second<=s[i].second) ans=max(ans,tot-(num[1][s[j].first-1]-num[1][s[i].first-1])-(num[1][s[i].second]-num[1][s[j].second])-(num[2][s
    [j].second]-num[2][s[j].first-1])); else ans=max(ans,tot-(num[1][s[j].first-1]-num[1][s[i].first-1])-(num[1][s[j].second]-num[1][s[i].second])-(num
    [2][s[i].second]-num[2][s[j].first-1])); } printf("%d ",ans); return 0; }

    D .Stressful Training

    题意:有N台电脑,每台电脑初始电量a[],每单位时间掉电b[],现在给一个充电器,这个充电器同一单位时间只能给一个电脑充电,问每单位时间至少充多少,满足每台电脑都至少坚持K时间。

    思路:二分X,二分之后这么写呢,是线性的呢。 求出每个人最晚的一些充电时间,然后总量不大于K,然后就是线性的向前摊平,如果同一时间个数大于1,则false。

    这两个限制使得每次二分是线性的。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,w,v) for(int i=w;i<=v;i++)
    using namespace std;
    const int maxn=200010;
    ll a[maxn],b[maxn],ans=-1;int N,K,vis[maxn];
    bool check(ll x)
    {
        int cnt=0; rep(i,1,K) vis[i]=0;
        rep(i,1,N){
            ll L=a[i];
            while(L-b[i]*(K-1)<0){
                int t=L/b[i]+1;
                if(L/b[i]+1<=K) vis[L/b[i]+1]++;
                cnt++; if(cnt==K) return false;
                L+=x;
            }
        }
        for(int i=K;i>1;i--) {
            if(vis[i]) vis[i-1]+=vis[i]-1;
        }
        if(vis[1]>1) return false;
        return true;
    }
    int main()
    {
        ll L=0,R=1e18,Mid;
        scanf("%d%d",&N,&K);
        rep(i,1,N) scanf("%lld",&a[i]);
        rep(i,1,N) scanf("%lld",&b[i]);
        while(L<=R){
            Mid=(L+R)/2;
            if(check(Mid)) R=Mid-1,ans=Mid;
            else L=Mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }

    E .Knapsack

    题意:给定8种物体的个数a[],重量分别对应1到8,给定W,问选处的不超过W的最大重量。 (W<1e18,a<1e16)

    思路:二进制拆分物体,然后暴力背包,可能会空间爆炸,用ans减去没用的一些空间就够了。

    这样的话,物体要从大到小排序,这样才能保证map的空间,以及减枝效果。

    (这是比较暴力的做法了,有更优美的解法

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    map<ll,bool>mp,tmp;
    map<ll,bool>::iterator it;
    const int maxn=20000;
    ll ans,W,a[maxn],v[maxn],sum[maxn]; int tot,cnt;
    int main()
    {
        scanf("%lld",&W);
        for(int i=1;i<=8;i++){
            scanf("%lld",&a[i]);
            if(!a[i]) continue; cnt++; ll t=1;
            ans=max(ans,min(W/i,a[i])*i);
            while(1){
                tot++; v[tot]=min(t,a[i])*i;
                a[i]-=min(t,a[i]); t=t*2;
                if(!a[i]) break;
            }
        }
        if(cnt==1){
            printf("%lld
    ",ans); return 0;
        }
        sort(v+1,v+tot+1); reverse(v+1,v+tot+1);
        for(int i=tot;i>=1;i--) sum[i]=sum[i+1]+v[i];
        mp[0]=true;
        for(int i=1;i<=tot;i++){
            tmp.clear();
            for(it=mp.begin();it!=mp.end();it++){
                ll x=it->first;
                tmp[x]=true;
                if(x+v[i]<=W) tmp[x+v[i]]=true;
            }
            mp.clear();
            for(it=tmp.begin();it!=tmp.end();it++){
               if(it->first+sum[i+1]<ans) continue;
               mp[it->first]=true;
               ans=max(it->first,ans);
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }

    F .Clear the String

    题意:给定长度为N的字符串,每次可以删去一段连续的相同字符,求最小删去次数。(N<500)

    思路:区间DP,反过来就是“刷墙”这种题:每次可以刷一段,问最少刷的次数。 如果col[L]=col[R],我们可以先刷[L,R],然后去刷[L+1,R-1];如果中间有相同的,还可以分子区间。所以是个需要枚举中间点的O(N^3)区间DP。(比赛的时候想N^2做,WA了。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,w,v) for(int i=w;i<=v;i++)
    using namespace std;
    const int maxn=510;
    int dp[maxn][maxn]; char a[maxn];
    int main()
    {
        int N,tot=1; scanf("%d%s",&N,a+1);
        rep(i,2,N){
            if(a[i]!=a[i-1]) a[++tot]=a[i];
        }
        N=tot;
        memset(dp,0x3f,sizeof(dp));
        rep(len,1,N){
            rep(L,1,N-len+1){
                int R=L+len-1;
                if(len==1) dp[L][R]=1;
                else if(len==2) dp[L][R]=(a[L]==a[R]?1:2);
                else {
                    dp[L][R]=len;
                    if(a[L]==a[R]) dp[L][R]=min(dp[L+1][R],dp[L][R-1]);
                    else{ dp[L][R]=min(dp[L+1][R],dp[L][R-1])+1;
                       rep(k,L,R) dp[L][R]=min(dp[L][R],dp[L][k]+dp[k][R]-1);
                    }
                }
            }
        }
        printf("%d
    ",dp[1][N]);
        return 0;
    }
  • 相关阅读:
    根据某字符(字符串)分割字符串
    call函数心得
    Git之常用命令
    ES6之async与await
    CSS之 sass、less、stylus 预处理器的使用方式
    JavaScript之继承
    vue之keep-alive的使用
    CSS之单行、多行文本溢出显示省略号
    Vue之 watch、computed、filter之间的区别与使用场景
    Vue之watch监听对象中某个属性的方法
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10485608.html
Copyright © 2020-2023  润新知