• Educational Codeforces Round 76 (Rated for Div. 2)E(dp||贪心||题解写法)


    题:https://codeforces.com/contest/1257/problem/E

    题意:给定3个数组,可行操作:每个数都可以跳到另外俩个数组中去,实行多步操作后使三个数组拼接起来形成升序。

       输出最小操作次数

    dp:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    int dp[M][3];
    int a[M];
    ///dp[i][0]表示前i个数全属于第一个数组所要花费的最小代价
    ///dp[i][1]表示前i个数全属于第一、二个数组所要花费的最小代价
    ///!!dp[i][1]必须要保证前i个数是要连续的属于第一个数组,和连续的属于第一个数组前后分布
    int main(){
        int k1,k2,k3;
        scanf("%d%d%d",&k1,&k2,&k3);
        int n=k1+k2+k3;
        for(int i=1,x;i<=k1;i++){
            cin>>x;
            a[x]=0;
        }
        for(int i=1,x;i<=k2;i++){
            cin>>x;
            a[x]=1;
        }
        for(int i=1,x;i<=k3;i++){
            cin>>x;
            a[x]=2;
        }
        for(int i=1;i<=n;i++){
            dp[i][0]=dp[i-1][0]+(a[i]==0?0:1);
            dp[i][1]=min(dp[i-1][0],dp[i-1][1])+(a[i]==1?0:1);
            dp[i][2]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+(a[i]==2?0:1);
        }
        cout<<min(dp[n][0],min(dp[n][1],dp[n][2]));
        return  0;
    }
    View Code

    贪心:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    int a[M],b[M];
    int main(){
        int n;
        int k1,k2,k3;
        scanf("%d%d%d",&k1,&k2,&k3);
        n=k1+k2+k3;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+k1);
        sort(a+k1,a+k1+k2);
        sort(a+k1+k2,a+n);
        int tot=0;
        for(int i=0;i<n;i++){
            if(b[tot]<a[i])
                b[++tot]=a[i];
            else{
                int pos=upper_bound(b,b+tot,a[i])-b;
                b[pos]=a[i];
            }
    
        }
        printf("%d
    ",n-tot);return 0;
    }
    View Code

     题解:枚举R,R往后的给第三个选手,然后在R的左边部分确定一个L,使其价值最优,

       考虑对于确定的L,R,答案就是,不属于L,R分割出来的数组对应的位置。

       比如L前面的数组我们要挑出属于第二,三数组的数

       这个说的就是上面的东西,也就是当前L,R的答案cnt(L,2)+cnt(L,3)+cnt(m,1)+cnt(m,3)+cnt(r,1)+cnt(r,2)

       分析:第二、四、五、六项我们可以通过枚举的R的位置来求到

          记x为第一项和第三项的和,即x=cnt(L,2)+cnt(m,1);

          现在只要知道x我们就可以算这个位置的答案了

          记posval=cnt(L,1)-cnt(L,2),我们要操作数最小,肯定要posval最大,因为posval大说明在L前面有越多满足属于第一个选手的题目。

          这时我们发现,posval+x=cnt(L,1)+cnt(m,1),这个表示R前面1的个数,这个可以很轻易的求得;

          x=cnt(R,1)-posval

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    int a[M];
    int L[10],R[10];
    int main(){
        int k1,k2,k3;
        scanf("%d%d%d",&k1,&k2,&k3);
        int n=k1+k2+k3;
        for(int x,i=1;i<=k1;i++){
            scanf("%d",&x);
            a[x]=1;
        }
        for(int x,i=1;i<=k2;i++){
            scanf("%d",&x);
            a[x]=2;
        }
        for(int x,i=1;i<=k3;i++){
            scanf("%d",&x);
            a[x]=3;
        }
        int ans=0,posval=0;
        for(int i=1;i<=n;i++)
            if(a[i]!=3)
                ans++;
        for(int i=1;i<=n;i++)
            R[a[i]]++;
        for(int i=1;i<=n;i++){
            L[a[i]]++;
            R[a[i]]--;
            posval=max(posval,L[1]-L[2]);///最佳的位置
            int sum=R[1]+R[2]+L[3]+L[1]-posval;
            ans=min(ans,sum);
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    第46课.继承中的构造与析构
    第45课.不同的继承方式
    第44课.继承中的访问级别
    第43课.继承的概念和意义
    [文件系统]文件系统学习笔记(三)---目录项缓存dentry
    [文件系统]文件系统学习笔记(二)---task_struct
    [文件系统]文件系统学习笔记(一)---基本概念以及inode
    [Linux]进程(十二)--task_struct结构体
    [Linux]进程——用户态编程相关
    [linux]进程(十一)——进程权能
  • 原文地址:https://www.cnblogs.com/starve/p/11864900.html
Copyright © 2020-2023  润新知