yfl的题qwq
题目描述
为了战胜yfl,dtx采用了最先进的外挂,他可以使用游戏中的所有卡牌,但是 由于外挂设计者ljl改颓炉石传说了,所以每张卡牌只能使用一次,并且每一次只能使用编号相邻的两张卡牌,如果编号为i和编号为i+1的两张卡牌被使用了,那么编号为i+2的卡牌编号变为i,依次类推。
此外,每张卡牌还有两个属性,分别是圣水花费和伤害值,如果两张卡牌的圣水花费总额大于K,那么这两张卡牌就不可以同时使用,每使用一张卡牌就会对 yfl造成伤害,邪恶的dtx希望对yfl造成的伤害值最大,请问该伤害值最大是多少?
输入格式
第一行为两个正整数n,K,代表一共有多少种卡牌和圣水最大上限。
接下来n行,每行为两个正整数ai,bi代表该卡牌的圣水花费和伤害值。
输出格式
输出仅一个正整数,代表最大伤害。
说明/提示
对于100%的数据,ai,bi,K≤10^9。
数据点 n≤ 1-3 20 4-6 100 7-8 200 9-10 800
一眼区间DP...
但是具体就挺难想的...我想了好久qaq
因为只能同时使用相邻两张牌,所以每个有贡献的区间长度都是偶数,
也就是说只用枚举长度为偶数的区间!(一开始我还以为是要分奇偶)
状态转移方程:f[i][j]表示牌i~j的最大伤害,k是断点
f[i][j] = max( f[i][k]+f[k+1][j],f[i+1][j-1]+b[i]+b[j](a[i]+a[j]<=k) )
也就是两部分合并,或中间的全部合并,加上最两边的(保证花费<=k)。
如何统计答案?
状态转移方程:g[i]表示前i张牌所能达到的最大价值
g[i] = max(g[i-1],g[j]+f[j+1][i])
这里的j也是每次+2。注意,如果i是奇数的话j就要从1枚举,反之从0枚举。(这里一开始wa了)
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #define Darcy amour using namespace std; const int maxn = 1005; const int INF = 0x3f3f3f3f; int n,k; long long a[maxn],b[maxn],f[maxn][maxn],g[maxn]; int main() { scanf("%d%d",&n,&k); for(int i = 1; i <= n; i++) scanf("%lld%lld",&a[i],&b[i]); memset(f,-INF,sizeof(f)); for(int i = 1; i <= n-1; i++) if(a[i]+a[i+1] <= k) f[i][i+1] = b[i]+b[i+1]; for(int len = 4; len <= n; len += 2) for(int i = 1; i+len-1 <= n; i++) { int j = i+len-1; if(a[i]+a[j] <= k) f[i][j] = max(f[i][j],f[i+1][j-1]+b[i]+b[j]); for(int k = i+1; k < j-1; k += 2) f[i][j] = max(f[i][j],f[i][k]+f[k+1][j]); } for(int i = 2; i <= n; i++) { g[i] = g[i-1]; for(int j = i%2; j < i-1; j+=2) g[i] = max(g[i],g[j] + f[j+1][i]); } printf("%lld",g[n]); return 0; }