有 n n n张卡片,每张卡片有 n a m e , c o l o r , p o w e r name,color,power name,color,power属性,给出 5 5 5个特殊的 n a m e name name, 1 1 1个特殊的 c o l o r color color。总得分定义为卡片的 p o w e r power power之和乘 b o n u s bonus bonus系数,初始是 b o n u s bonus bonus为 1 1 1,每张卡片满足 n a m e name name是特殊的时候 b o n u s + 0.1 bonus+0.1 bonus+0.1, c o l o r color color是特殊的时候 b o n u s + 0.2 bonus+0.2 bonus+0.2。需要从 n n n张卡内选出 5 5 5张,使得他们 n a m e name name两两互异,并且使得总得分最大
明显是个分组背包,但如何定义状态?若我们像普通的分组背包,定义
f
[
i
]
f[i]
f[i]为已装
i
i
i容量的物品的最大价值,实际上题目的价值是随前面的总价值变化而变化的,难以转移,并且似乎考虑不到所有的状态。造成这一现象的原因是
b
o
n
u
s
bonus
bonus在变化,于是考虑将
b
o
n
u
s
bonus
bonus加入状态,定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]为装了容量为
i
i
i的物品,此时
b
o
n
u
s
=
10
×
j
bonus=10\times j
bonus=10×j的最大
p
o
w
e
r
power
power和为多少,这样就能够考虑到所有状态了。显然我们首先需要对卡片按名字分组,于是不妨来一次排序,然后双指针找出同名的一段,枚举加入的卡片为
k
k
k,有
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
v
a
l
]
+
a
[
k
]
.
p
o
w
e
r
)
;
dp[i][j]=max(dp[i][j],dp[i-1][j-val]+a[k].power);
dp[i][j]=max(dp[i][j],dp[i−1][j−val]+a[k].power);
答案就是
m
a
x
(
d
p
[
5
]
[
i
]
+
d
p
[
5
]
[
i
]
∗
i
/
10
)
max(dp[5][i]+dp[5][i]*i/10)
max(dp[5][i]+dp[5][i]∗i/10)。需要注意初始化时只有
d
p
[
0
]
[
0
]
=
0
dp[0][0]=0
dp[0][0]=0,其他都置为负无穷,以保证转移的源头都是状态
(
0
,
0
)
(0,0)
(0,0)
#ifndef stdjudge
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using ll=long long;
const int N=1e5+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=998244353;
struct poker
{
string name,color;
int power;
bool operator<(const poker& x) const {
return name<x.name;
}
}a[N];
unordered_map<string,bool>map1;
string color;
int n;
ll dp[6][16];
int getval(int x) {
return map1.count(a[x].name)+2*(a[x].color==color);
}
int main()
{
#ifdef stdjudge
freopen("in.txt","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int t; cin>>t;
while(t--)
{
cin>>n; map1.clear();
for(int i=1;i<=n;i++) cin>>a[i].name>>a[i].color>>a[i].power;
for(int i=1;i<=5;i++)
{
cin>>color;
map1[color]=true;
}
cin>>color;
sort(a+1,a+1+n);
for(int i=0;i<=5;i++)
for(int j=0;j<=15;j++) dp[i][j]=-INF;
int l=1,r=1; dp[0][0]=0;
while(l<=n)
{
while(r+1<=n&&a[r+1].name==a[l].name) r++;
for(int i=5;i>=1;i--)
{
for(int j=0;j<=15;j++)
{
for(int k=l;k<=r;k++)
{
int val=getval(k);
if(j>=val) dp[i][j]=max(dp[i][j],dp[i-1][j-val]+a[k].power);
}
}
}
l=++r;
}
ll ans=-INF;
for(int i=0;i<=15;i++) ans=max(ans,dp[5][i]+dp[5][i]*i/10);
cout<<ans<<'\n';
}
return 0;
}