#狀壓dp,貪心#CF1316E Team Building
阿新 • • 發佈:2020-08-19
題目
為了組織一支排球隊,你需要為隊伍裡的\(p\)個不同的位置,從\(n\)個人中選出\(p\)個人,
且每個位置上都恰好有一個人。另外還需要從剩下的人中選出恰好\(k\)個人作為觀眾。
對於第\(i\)個人,已知他作為觀眾時能為隊伍增加\(a_i\)點力量,
還有他在隊伍的第\(j\)個位置上時能為隊伍增加\(s_{i,j}\)點力量。
請問這隻排球隊力量的最大值是多少?
分析
由於\(p\)很小,考慮狀壓dp,
設\(dp[i][s]\)表示前\(i\)個人選取為隊員的狀態為\(s\)時產生的最大力量
為了讓觀眾力量更大,按照貪心思想肯定要先按觀眾力量從大到小排序,
還要保證選取的觀眾人數恰好等於\(k\)
程式碼
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define rr register using namespace std; const int N=100011; typedef long long lll; struct rec{int w,z[7];}a[N]; int n,m1,m2,al,xo[N]; lll dp[128]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } bool cmp(rec x,rec y){return x.w>y.w;} inline void Max(lll &a,lll b){a=a>b?a:b;} signed main(){ n=iut(),m1=iut(),m2=iut(),al=1<<m1; for (rr int i=1;i<al;++i) xo[i]=xo[i&(i-1)]+1; for (rr int i=1;i<=n;++i) a[i].w=iut(); for (rr int i=1;i<=n;++i) for (rr int j=0;j<m1;++j) a[i].z[j]=iut(); sort(a+1,a+1+n,cmp); memset(dp,0xcf,sizeof(dp)),dp[0]=0; for (rr int i=1;i<=n;++i) for (rr int j=al-1;~j;--j){ if (dp[j]>=0) dp[j]+=a[i].w*(i-xo[j]<=m2); for (rr int p=0;p<m1;++p) if ((j>>p)&1) Max(dp[j],dp[j^(1<<p)]+a[i].z[p]); } return !printf("%lld",dp[al-1]); }