codeforces 467C.George and Job 解题报告

题目链接:http://codeforces.com/problemset/problem/467/C

题目意思:给出一条含有 n 个数的序列,需要从中找出 k 对,每对长度为 m 的子序列,使得 找出来的k对序列的总和相同。注意,同一个数不能在两个子序列中。

    首先用了很暴力的做法,赛后发现过不了test 5 的时候,就知道需要用到 dp 来做了。看了这个人的提示:

    

    其实看完这个状态转移方程,就觉得这题不太难了。

    dp[i][j]: 前 i 个数中,选择 j pairs 可以获得的最大和。

    那么对于第 i 个数来说,有不选和选择的两种情况。如果不选第 i 这个数 ,即dp[i-1][j],表示前 i 个数,选择 j pairs 获得的最大和 = 前i-1个数中选择 j pairs 可以获得的最大和;如果选第 i 个数,状态就转移到 dp[i-m][j-1] + sum[i] - sum[i-m],这个 sum[i]- sum[i-m] 会成为新的一个pair,前面那个第 i-m 个数就不要选。

     虽然运行时间有点慢,但好在非常容易理解。

    

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 const int maxn = 5000 + 10;
 9 ll sum[maxn], dp[maxn][maxn], p;
10 
11 int main()
12 {
13     int n, m, k;
14     while (scanf("%d%d%d", &n, &m, &k) != EOF)
15     {
16         scanf("%lld", &p);
17         sum[1] = p;
18         for (int i = 2; i <= n; i++)
19         {
20             scanf("%lld", &p);
21             sum[i] = sum[i-1] + p;
22         }
23         memset(dp, 0, sizeof(dp));
24         dp[m][1] = sum[m];
25         for (int j = 1; j <= k; j++)
26         {
27             for (int i = m+1; i <= n; i++)
28             {
29                 dp[i][j] = max(dp[i-1][j], dp[i-m][j-1]+sum[i]-sum[i-m]);
30             }
31         }
32         printf("%lld\n", dp[n][k]);
33     }
34     return 0;
35 }
View Code

 

posted @ 2014-09-22 00:10  windysai  阅读(484)  评论(0编辑  收藏  举报