一天,明明在玩纸牌游戏。 游戏规则是:一共有 n 张牌,每张牌上有一个花色 c 和一个点数 v,花色不超过 k 种。将这些牌依次放入一列牌的末端。若放入之前这列牌中已有与这张牌花色相同的牌,你可以选择将这张牌和任意一张花色相同的牌之间的所有牌全部取出队列(包括这两张牌本身),并得到与取出的所有牌点数和相同的分数。现在已知 明明 把这 n 张牌放入队列的顺序,求他最多能得多少分。 输入顺序即为 明明 放入队列的顺序。即,ci表示第 i 张放入的牌的花色,vi表示第 i 张放入的牌的点数。
第一行两个整数 n,k。(1
Output
输出一行一个整数,表示最多能得到的分数。
Sample Input
7 3
1 2 1 2 3 2 3
1 2 1 2 3 2 3
Sample Output
13
Hint
样例解释 1
第 1 步,向队列加入 1。现在的队列:1
第 2 步,向队列加入 2。现在的队列:1,2
第 3 步,向队列加入 1。现在的队列:1,2,1
第 4 步,向队列加入 2,取出 2,1,2。现在的队列:1
第 5 步,向队列加入 3。现在的队列:1,3
第 6 步,向队列加入 2。现在的队列:1,3,2
第 7 步,向队列加入 3,取出 3,2,3。现在的队列:1
题解:dp,优化记录
这道题不难想到用dp,状态转移方程也很容易想到
三个数组,col:花色,sum:前缀和,MAX:f[i-1]-sum[i-1];
f[i]=f[i-1];
if(col[i]==col[j])
f[i]=max(f[i],f[j-1]+sum[i]-sum[j-1])
但我们发现这个需要两重循环,会爆时间,所以需要优化一下
这里提供一个方法:
我们使用数组 MAX[col[i]] 记录已经出现过的花色为 col[i] 的 f[i-1]-sum[i-1]
这样当下一个花色同样为 col[i] 的花色出现时,当前的 col[i] 既是那时候的 col[j]
而MAX里的内容也就是那时候的 f[j-1] -sum[j-1]
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
- typedef long long LL;
- const int N = 2e5 + 5;
- int n, k;
- LL sum[N], col[N], MAX[N];
- LL f[N];
- int main() {
- scanf("%d%d", &n, &k);
- for (int i = 1; i <= n; i++) {
- scanf("%lld", & col[i]);
- }
- for (int i = 1; i <= n; i++) {
- scanf("%lld", &sum[i]);
- sum[i] += sum[i - 1];
- }
- memset(MAX, 192, sizeof(MAX));
- for (int i = 1; i <= n; i++) {
- f[i] = max(f[i - 1], MAX[col[i]] + sum[i]);
- MAX[col[i]] = max(MAX[col[i]], f[i - 1] - sum[i - 1]);
- }
- printf("%lld\n", f[n]);
- return 0;
- }