Luogu T104491 皇室战争

传送门(然而有权限)

yfl的题qwq

题目描述

为了战胜yfldtx采用了最先进的外挂,他可以使用游戏中的所有卡牌,但是 由于外挂设计者ljl改颓炉石传说了,所以每张卡牌只能使用一次,并且每一次只能使用编号相邻的两张卡牌,如果编号为i和编号为i+1的两张卡牌被使用了,那么编号为i+2的卡牌编号变为i,依次类推。

此外,每张卡牌还有两个属性,分别是圣水花费和伤害值,如果两张卡牌的圣水花费总额大于K,那么这两张卡牌就不可以同时使用,每使用一张卡牌就会对 yfl造成伤害,邪恶的dtx希望对yfl造成的伤害值最大,请问该伤害值最大是多少?

输入格式

第一行为两个正整数n,K,代表一共有多少种卡牌和圣水最大上限。

接下来n行,每行为两个正整数ai,bi代表该卡牌的圣水花费和伤害值。

输出格式

输出仅一个正整数,代表最大伤害。

说明/提示

对于100%的数据,ai,bi​,K10^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;
}
View Code
原文地址:https://www.cnblogs.com/mogeko/p/11738123.html