两道题都是结束以后才想出来。。。两题都只过了20%,哭了。
第一题应该是只有当所有数字都出现偶数次时候第二个人才能赢,其他情况都是第一个人赢。
第二题我以为是只能取每一层的一头一尾两个,写了一个dp,只过了20%,结束以后我发现数据给的n和c最大为100,m最大为10000,说明如果m >= n * c,所有物品都可以拿走,所以每一层如果已经拿了第1个和第c个,那就还可以继续拿第2个和第c-1个。
个人觉得是个背包dp,然后时间不够呀!!!
好气!结束了才想到。
(代码有问题。。。不好意思,我删掉重写)
昨晚躺在床上突然发现之前这样子贪心找到的并不是最优解,思来想去,发现可以用滑动窗口预处理出当前层取x个物品可以获得的最大价值存在数组中,然后dp,复杂度O(n*(c^2+m*c)),我觉得应该没有问题,欢迎大家指正!
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[110], val[110]; int dp[10010]; int main() { int n, m, c; cin >> n >> m; memset(dp, 0, sizeof dp); for (int i = 0; i < n; i++){ int sum = 0;//求当前层物品价值和 cin >> c; for (int j = 0; j < c; j++){ cin >> a[j]; sum += a[j]; } memset(val, 0, sizeof val); for (int k = 1; k <= c; k++){ // 当前层获得k件物品可得的最大值存入val int index = 0, now = 0;//滑动窗口,窗口大小为c-k while (index < c-k){ now += a[index]; index++; } val[k] = max(val[k], sum-now); while (index < c){ now += a[index]; now -= a[index-c+k]; val[k] = max(val[k], sum-now); index++; } } for (int j = m; j > 0; j--) for (int k = 1; k <= min(j, c); k++) dp[j] = max(dp[j], dp[j-k]+val[k]); } cout << dp[m] << endl; return 0; }
全部评论
(17) 回帖