zoukankan      html  css  js  c++  java
  • 牛客周周练7 C加强版

    牛客周周练7 C

    传送门

    给你一个(n,k(n<=400,k<=(n*n/2)))。再给你一个01串,0表示这天放假,不工作,1表示这天上班,但可以请假。连续上i天班的代价是i,现在问代价不超过k时,最多工作多少天。

    (dp[i][j])为考虑到第i天时,工作了j天。转移的时候,我们只需要考虑最后一段连续1的长度就可以转移了。很简单。

    //copied from rk1 @牛客竞赛0331号
    #include<bits/stdc++.h>
    using namespace std;
    int DP[405][405]={0},i,j,k,n,m;
    char R[405];
    int main(){
        scanf("%d%d%s",&n,&m,R+1);
        for(i=1;i<=n;i++)DP[0][i]=1e9;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++){
                DP[i][j]=DP[i-1][j];
                if(R[i]=='0'||j>i) continue;
                for(k=1;k<=j&&R[i-k+1]!='0';k++)
                    DP[i][j]=min(DP[i][j],DP[max(0,i-k-1)][j-k]+k*(k+1)/2);
            }
        for(i=n;i>=1;i--) if(DP[n][i]<=m) break;
        printf("%d
    ",i);
    }
    

    bonus:(n<=2e5,k<=1e9),答案是多少呢?

    我们考虑初始的每一段连续的1。这个时候,我们只需要考虑给每一段连续的1再添加一个0的时候,减小的代价就好了(容易想到是均分的时候代价最小),把这些代价扔进一个优先队列里,贪心的选取。容易看出来这个是满足贪心的性质的。

    #include<bits/stdc++.h>
    
    #define PB push_back
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int N = 200'005;
    
    VI seg;
    
    int n, k;
    
    char s[N];
    
    priority_queue<tuple<LL,int,int>> q;
    
    LL calc(int len, int time){
        int x=(len-time)/(time+1);
        int y=len-time-x*(time+1);
    
        LL res=0;
        res+=1ll*x*(x+1)*(time+1-y)/2;
        res+=1l*(x+1)*(x+2)*y/2;
    
        return res;
    }
    
    int main(){
        n=read(),k=read();
        scanf("%s",s+1);
    
        int cur=(s[1]=='1');
        for(int i=2;i<=n;++i){
            if(s[i]=='0'){
                seg.PB(cur);
                cur=0;
            }else{
                ++cur;
            }
        }
    
        if(cur>0)seg.PB(cur);
    
        LL sum=0;
        for(int i=0;i<SZ(seg);++i){
            sum+=calc(seg[i],0);
            q.push(make_tuple((calc(seg[i],0)-calc(seg[i],1)),seg[i],1));
        }
    
    
        while(sum>k){
            LL x;int y,z;
            tie(x,y,z)=q.top();
            q.pop();
            sum-=x;
            q.push(make_tuple((calc(y,z)-calc(y,z+1)),y,z+1));
        }
    
        int res=0;
        while(!q.empty()){
            LL x;int y,z;tie(x,y,z)=q.top();
            q.pop();
            res+=y-z+1;
        }
    
        cout<<res;
    
    
        return 0;
    }
    
    
  • 相关阅读:
    【搞笑】各种程序评测结果
    【UVA】P1510 Neon Sign
    【转载】实用:根号怎么打出来? <引自百度>
    【转载】C++中的模板template <typename T>
    * ! THUSC2017杜老师
    * ! THUSCH2017巧克力
    ! BJOI2019光线
    ! BJOI2019奥术神杖
    ! TJOI/HEOI2016字符串
    ! TJOI/HEOI2016求和
  • 原文地址:https://www.cnblogs.com/JohnRan/p/12920546.html
Copyright © 2011-2022 走看看