牛客周周练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;
}

原文地址:https://www.cnblogs.com/JohnRan/p/12920546.html