题意:
就是给你n次比赛,每次比赛上榜需要的分数,你的初始分数,每次比赛有4个分数可以选择,还有m次魔法,如果在某一场用魔法,那么这场的后两个分数也可以挑。如果不用魔法就只能从前两个分数中挑一个。当然你可以让比赛的顺序随便改变。
思考:
刚开始看了看人过的不多,然后最后看了看,难道是dp吗,但是感觉dp又不能写。最后看了一眼数据我范围,n和m才20,那么很明显了。二进制枚举所有魔法用在哪场比赛。但是这里又卡住我了,从n位中选m位,这咋二进制。以前用的从n位中直接随便选的那种。可能昨天太傻逼了,其实还是直接枚举0到1ll<<n,然后看看如果选i的时候1的位数大于m了就不要,跳过就行了。所以每次比赛都尽可能选最大的,然后从大到小排序贪心一下。
值得注意的呢是,虽然2的20次方挺大的,但是真正能到下面的很少,所以最终是不大的。还有就是对于标记的能用数组vis就用数组,unordered其实还是有点慢,特别是用的次数特别多的时候。
代码:
int T,n,m,k;
int sc[N];
int va[N],vb[N],vc[N],vd[N];
int vis[N];
signed main()
{
IOS;
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>sc[i];
for(int i=1;i<=n;i++) cin>>va[i]>>vb[i]>>vc[i]>>vd[i];
int ans = 0;
for(int i=0;i<(1ll<<n);i++)
{
int cnt = 0;
for(int j=1;j<=n;j++) vis[j] = 0;
for(int j=0;j<n;j++) if(i>>j&1) vis[j+1] = 1,cnt++;
if(cnt>m) continue;
vector<int > anw;
for(int j=1;j<=n;j++)
{
int maxn = max(va[j],vb[j]);
if(vis[j]) maxn = max(maxn,max(vc[j],vd[j]));
anw.pb(maxn);
}
sort(anw.begin(),anw.end(),greater<int>());
int sum = k,res = 0;
for(int j=1;j<=n;j++)
{
sum += anw[j-1];
if(sum>=sc[j]) res++;
}
ans = max(ans,res);
}
cout<<ans;
return 0;
}
总结:
不要太慌张,一点一点思考。