Round544div3E(1133E)

一、题目链接

https://codeforces.com/problemset/problem/1133/E

二、思路

显然要使用dp,因为中间有部分人不会选取。

令$dp[i][j]$表示在前$i$个人里面选择j组所能得到的最大人数。接下来就是0-1背包思想了。

对于第$i$个人,如果不选,那么$dp[i][j]=max(dp[i][j],dp[i-1][j])$;

如果选,那么$dp[i][j]=max(dp[i][j],dp[k][j-1]+i-k),0 \le k < i$。

这转移方程的时间复杂度是$O(N^3)$,显然会超时。

注意到,如果$a[i]==a[i-1]$,如果选择了$a[i-1]$,那么$a[i]$一定会选择。否则$a[i]$一定不会被选择。也就是说,如果两个人的数值相同,要么这两个人同时被选,要么同时都不被选。那么,可以对整个$a$数组去重,并记录每个数值代表的人数。令$a'$为去重后的数组,对于去重后的数组$a'$,上述式子$k$的选取不超过$5$,然后,把转移的代价由$i-k$改为$\sum\limits_{x=k+1}^{i}cnt[a'[x]]$即可。

三、代码

#include<bits/stdc++.h>

using namespace std;
const int N = 5e3 + 10;
int n, k;
int a[N];
int dp[N][N];
unordered_map<int, int> cnt;

int main() {
    cin >> n >> k;
    for (int i = 0; i < n; ++i)scanf("%d", a + i), cnt[a[i]]++;
    sort(a, a + n);
    int m = unique(a, a + n) - a;
    for (int i = 0; i < m; ++i) {
        for (int j = 1; j <= k; ++j) {
            int cc = 0;
            for (int x = i; x >= 0; x--) {
                if (a[x] < a[i] - 5)break;
                cc += cnt[a[x]];
                if (i > 0)dp[i][j] = max(dp[i][j], dp[i - 1][j]);
                if (x > 0)dp[i][j] = max(dp[i][j], dp[x - 1][j - 1] + cc);
                else if (x == 0)dp[i][j] = max(dp[i][j], cc);
            }
        }
    }
    cout << dp[m - 1][k] << endl;
    return 0;
}
/*

 6 1
 2 7 12 13 14 12

 11 4
 2 7 13 12 15 17 23 24 25 31 36

 7 2
 2 4 10 11 17 18 19

 7 1
 1 1 1 6 6 6 7

 11 2
 1 2 2 7 9 15 16 23 24 23 25

**/

 

posted @ 2019-03-10 09:32 fuzhihong0917 阅读(...) 评论(...) 编辑 收藏