1883 升级卡牌
Noder在玩炉石,现在轮到Noder进行攻击了,在这一轮中,Noder可以选择8张牌对敌人进行攻击,一张牌使用一次就会消失。在攻击之前Noder可以对他的牌进行升级,然后就可以发挥更大的威力。但是升级是需要钱的。现在Noder手上有M块钱,N张牌。第i张牌的等级范围是1到K[i];第i张牌在第j个等级的时候攻击力是A[i][j]。每次升级的时候,只能给一张牌升一级,但是可以进行多次升级。将第i张牌从第j级升到第j+1级,需要C[i][j]块金钱。在未做任何升级操作的时候,第i张牌的等级是L[i]。
现在Noder想用这些钱的一部分对某些牌进行升级,最后使用8张牌去攻击对手,最后的目的是使得攻击力总和最大。
样例解释:
在样例1中,把前4张牌升级到等级3,把第5,第6张牌升级到等级2,最后两张牌不升级,那么最后的花费是(1+2)+(1+3)+(1+4)+(1+5)+1+1=20块,总攻击力是100+100+100+100+10+10+1+1=422
输入
多组测试数据。
第一行有一个整数T(1 ≤ T ≤ 10),表示测试数据的数目。
接下来有T组数据。
对于每一组数据,
第一行有两个整数M (1 ≤ M ≤ 1,000,000,000)和 N(8 ≤ N ≤ 12)
接下来有N个块。
每个块有三行,表示第i张牌的信息。
第一行有两个整数K[i] (1 ≤ K[i] ≤ 10)和 L[i]( 1 ≤ L[i] ≤ K[i])。
第二行有K[i]个整数A[i][1],A[i][2], ..., A[i][K[i]],表示每一个等级所对应的攻击力。
第三行有K[i]-1个整数C[i][1],C[i][2], ..., C[i][K[i]-1]。
输出
对于每一组数据,输出一个整数表示答案,占一行。
输入样例
样例输入1
2
20 8
3 1
1 10 100
1 2
3 1
1 10 100
1 3
3 1
1 10 100
1 4
3 1
1 10 100
1 5
3 1
1 10 100
1 6
3 1
1 10 100
1 7
3 1
1 10 100
1 8
3 1
1 10 100
1 9
30 10
4 1
1 10 100 200
1 2 3
3 1
1 10 100
2 4
3 1
1 10 100
3 6
4 2
1 10 100 200
4 8 16
3 1
1 10 100
5 10
3 1
1 10 100
6 12
3 1
1 10 100
7 14
3 1
1 10 100
8 16
3 1
1 10 100
9 18
3 1
1 10 100
10 20
输出样例
样例输出1
422
504
分析:
对于这个问题,那些不用牌很明显不会去升级,那么就要先确定哪些牌是用的,然后给这些牌升级,如果直接枚举哪些牌用,然后再枚举哪些牌升到什么等级,这样的复杂度是 C(12,8)∗108很明显会超时。
其实对于108这一步有优化,即把这8张牌分成两部分,然后分别先暴力求出所有组合,那么左边就是104种可能,右边也有104种可能,然后按照总的花费进行排序。最后枚举左边中的一个组合,去右边中找那些能够和他组合起来花费不超过M的,这儿可以用two point算法,因为花费已经有序了,那么随着左边的花费增大,右边的最大总花费是要减少的。
放代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 13;
const int M = 10100;
struct Node{
unsigned int a;int c;
Node(unsigned int _a=0,int _c=0){
a=_a; c=_c;
}
};
bool cmp(Node &a,Node &b){
return a.c<b.c;
}
int n,m,l[N],r[N],s[N],a[N][N],c[N][N];
unsigned int na; ll ans; int nc;
Node pp[M],qq[M]; int p,q;
void dfs1(int d){
if(nc>m) return ;
if(d>4){
pp[p].a=na; pp[p].c=nc;
p++; return;
}
int j=s[d];
for(int i=l[j];i<=r[j]&&~c[j][i];++i){
na+=a[j][i]; nc+=c[j][i];
dfs1(d+1);
na-=a[j][i]; nc-=c[j][i];
}
}
void dfs2(int d){
if(nc>m) return ;
if(d>8){
qq[q].a=na; qq[q].c=nc;
q++; return;
}
int j=s[d];
for(int i=l[j];i<=r[j]&&~c[j][i];++i){
na+=a[j][i]; nc+=c[j][i];
if(nc>m){
na-=a[j][i]; nc-=c[j][i];
break;
}
dfs2(d+1);
na-=a[j][i]; nc-=c[j][i];
}
}
void dfs(int d,int k){
if(n+k-d<8) return;
if(k>8){
p=q=0; na=nc=0;
dfs1(1); dfs2(5);
sort(pp,pp+p,cmp);
sort(qq,qq+q,cmp);
for(int i=p-1,j=0;i>=0;--i){
while(j<q&&qq[j].c+pp[i].c<=m){
if(na<qq[j].a) na=qq[j].a; j++;
}
if(ans<(ll)na+pp[i].a) ans=(ll)na+pp[i].a;
}
return;
}
s[k]=d; dfs(d+1,k+1);
dfs(d+1,k);
}
int main(){
int t; scanf("%d",&t);
while(t--){
scanf("%d %d",&m,&n); ans=0;
for(int i=1;i<=n;++i){
scanf("%d %d",&r[i],&l[i]);
for(int j=1;j<=r[i];++j) scanf("%u",&a[i][j]);
for(int j=2;j<=r[i];++j) scanf("%d",&c[i][j]);
c[i][l[i]]=0;
for(int j=l[i]+1;j<=r[i];++j){
c[i][j]+=c[i][j-1];
if(c[i][j]>m){
c[i][j]=-1; break;
}
}
}
dfs(1,1); printf("%lld\n",ans);
}
return 0;
}
337

被折叠的 条评论
为什么被折叠?



