贪心+状态压缩——cf1322C

/*
p个位置用来组队(有序)
k个观众(无序)
要求收益最大化,dp[i][S]表示前i个人的组队状态是S时的最大收益
先对a进行排序 
第i个人加入后有三种选择:
    找个位置组队: 挑一个S中为0的位置 
    不组队,去当观众/有可能当不成:如果i-cnt(S)>=k,那么当不成观众 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define ll long long
 
struct Node{
    ll a,s[7];
}b[N];
int cmp(Node &a,Node &b){return a.a>b.a;}
ll n,p,k,dp[N][1<<7],cnt[1<<7];

void prework(){
    for(int i=0;i<(1<<7);i++){
        int res=0;
        for(int j=0;j<7;j++)
            if(i>>j & 1)res++;
        cnt[i]=res;
    }
}

int main(){
    prework();
    cin>>n>>p>>k;
    for(int i=1;i<=n;i++)scanf("%lld",&b[i].a);
    for(int i=1;i<=n;i++)
        for(int j=0;j<p;j++)scanf("%lld",&b[i].s[j]);
    
    sort(b+1,b+1+n,cmp);
    
    memset(dp,-1,sizeof dp);
    dp[0][0]=0;
    
    for(int i=0;i<n;i++){
        for(int S=(1<<p)-1;S>=0;S--)if(dp[i][S]!=-1){
            //不组队 
            if(i-cnt[S]>=k)dp[i+1][S]=max(dp[i+1][S],dp[i][S]);
            else dp[i+1][S]=max(dp[i+1][S],dp[i][S]+b[i+1].a); 
            //组队
            for(int j=0;j<p;j++)if(!(S>>j & 1))
                dp[i+1][S|(1<<j)]=max(dp[i+1][S|(1<<j)],dp[i][S]+b[i+1].s[j]);
        }
    }    
    cout<<dp[n][(1<<p)-1]<<'\n';
} 

 

posted on 2020-03-10 15:41  zsben  阅读(225)  评论(0编辑  收藏  举报

导航