• [CF1316E] Team Building


    需要在 (n) 个人中选出 (p) 个人站着队伍中的各个位置上,再从剩下的 (n-p) 个人中选出 (k) 个人作为观众。第 (i) 个人作为观众可以有 (a_i) 的得分,作为队伍中第 (j) 个位置上的人可以有 (s_{i,j}) 的得分,求得分的最大值。(nleq 10^5, pleq 7)

    Solution

    将人按照 (a) 从大到小排序,这样如果敲定了哪些人是队伍,那么剩下的靠前的 (k) 个一定是观众

    考虑状压 DP,设 (f[i][j]) 表示考虑了前 (i) 个人,队伍中各个位置的状态为 (j) 的得分最大值,决策下一个人放在队伍的哪一个位置,或者不入队,如果不入队则判定如果 (i-popcount(j) leq k) 则去当观众

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 200005;
    
    struct item {
        int s[8],a;
        bool operator < (const item &b) {
            return a>b.a;
        }
    } a[N];
    int n,p,k,f[500],g[500];
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>n>>p>>k;
        for(int i=1;i<=n;i++) cin>>a[i].a;
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=p;j++) cin>>a[i].s[j];
        }
        sort(a+1,a+n+1);
        memset(g,-0x3f,sizeof g);
        g[0]=0;
        for(int i=1;i<=n;i++) {
            memset(f,-0x3f,sizeof f);
            for(int j=0;j<1<<p;j++) {
                for(int l=1;l<=p;l++) {
                    if((j&(1<<(l-1)))) {
                        int x=j^(1<<(l-1));
                        f[j]=max(f[j],g[x]+a[i].s[l]);
                    }
                }
                f[j]=max(f[j],g[j]+(i-__builtin_popcount(j)<=k?a[i].a:0));
            }
            memcpy(g,f,sizeof f);
        }
        cout<<f[(1<<p)-1];
    }
    
    
  • 相关阅读:
    寻找道路
    联合权值
    二分图
    最优贸易
    读入优化
    专属空间五——新世界(新闻浏览功能)中
    专属空间四——新世界(新闻浏览功能)上
    专属空间三——文件管理器
    专属空间二-记账本的实现
    专属空间一-主界面设计
  • 原文地址:https://www.cnblogs.com/mollnn/p/12460865.html
Copyright © 2020-2023  润新知