noip模拟赛 党
2017-10-23 08:56
183 查看
分析:一道非常恶心的dp题.每个人要么选或不选,很像是0-1背包,可以套用背包问题的状态,但是因为题目要求3个值,所以可以再加一维表示3个答案.
f[i][j][k][l][p][0/1/2]表示i个守门员,j个后卫,k个中锋,l个前锋,花费是p,最后一维是0则表示不考虑队长的价值,1是方案数,2是队长价值.在这个状态表示里省去了一维表示前多少个人,其实就是一个滚动数组,递推的时候要倒序枚举.因为队长的价值会被算两边,所以队长肯定是价值最大的,先对所有人排个序,枚举到第i个人的时候,就让第i个人当队长就行了,不需要再去枚举.然后根据题目说的那样更新0/1/2就可以了.
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int mod = 1000000000, inf = 0x7fffffff; int n, up[10], down[10], f[2][6][6][4][1010][3], ans0, ans1 = inf, ans2; int maxn; struct node { int id, v, c; }e[510]; bool cmp(node a, node b) { return a.v < b.v; } void init() { up[1] = 1; down[1] = 1; up[2] = 5; down[2] = 3; up[3] = 5; down[3] = 2; up[4] = 3; down[4] = 1; } void update(int i, int j, int k, int l,int p,int fangan, int jiazhi, int duizhang) { if (f[i][j][k][l][p][0] < jiazhi) { f[i][j][k][l][p][0] = jiazhi; f[i][j][k][l][p][1] = 0; f[i][j][k][l][p][2] = duizhang; } if (f[i][j][k][l][p][0] == jiazhi && f[i][j][k][l][p][2] < duizhang) { f[i][j][k][l][p][1] = 0; f[i][j][k][l][p][2] = duizhang; } if (f[i][j][k][l][p][0] == jiazhi && f[i][j][k][l][p][2] == duizhang) { f[i][j][k][l][p][1] += fangan; if (f[i][j][k][l][p][1] >= mod) f[i][j][k][l][p][1] = mod; } } void gengxin(int x) { for (int i = up[1] - (e[x].id == 1); i >= 0; i--) for (int j = up[2] - (e[x].id == 2); j >= 0; j--) for (int k = up[3] - (e[x].id == 3); k >= 0; k--) for (int l = up[4] - (e[x].id == 4); l >= 0; l--) if (i + j + k + l < 11) { for (int p = maxn - e[x].c; p >= 0; p--) if (f[i][j][k][l][p][1]) update(i + (e[x].id == 1), j + (e[x].id == 2), k + (e[x].id == 3), l + (e[x].id == 4), p + e[x].c,f[i][j][k][l][p][1], f[i][j][k][l][p][0] + e[x].v, e[x].v); } } int main() { init(); f[0][0][0][0][0][2] = -1; f[0][0][0][0][0][1] = 1; scanf("%d", &n); for (int i = 1; i <= n; i++) { char s[20]; scanf("%s", s + 1); scanf("%d%d", &e[i].v, &e[i].c); if (s[1] == 'G') e[i].id = 1; if (s[1] == 'D') e[i].id = 2; if (s[1] == 'M') e[i].id = 3; if (s[1] == 'F') e[i].id = 4; } scanf("%d", &maxn); sort(e + 1, e + 1 + n,cmp); for (int i = 1; i <= n; i++) gengxin(i); for (int i = down[1]; i <= up[1]; i++) for (int j = down[2]; j <= up[2]; j++) for (int k = down[3]; k <= up[3]; k++) for (int l = down[4]; l <= up[4]; l++) if (i + j + k + l == 11) for (int p = 0; p <= maxn; p++) if (f[i][j][k][l][p][1]) { int temp0 = f[i][j][k][l][p][0] + f[i][j][k][l][p][2]; int temp1 = p; int temp2 = f[i][j][k][l][p][1]; if (temp0 > ans0) { ans2 = 0; ans0 = temp0; ans1 = temp1; } if (temp0 == ans0 && temp1 < ans1) { ans1 = temp1; ans2 = 0; } if (temp0 == ans0 && temp1 == ans1) { ans2 += temp2; if (ans2 >= mod) ans2 = mod; } } printf("%d %d %d\n", ans0, ans1, ans2); return 0; }
相关文章推荐
- 2016.10.05【初中部 NOIP普及组 】模拟赛总结
- noip模拟赛 czy的后宫
- 2017.09.23【NOIP 普及组】模拟赛C组 总结
- NOIP欢乐模拟赛 T3 解题报告
- noip 模拟赛 After 17(递推+特殊的技巧)
- NOIP模拟赛13
- 【NOIP模拟赛】【数学真奇妙系列】纸盒子
- noip模拟赛 好元素 哈希表的第一题
- 【NOIP模拟赛】【乱搞AC】【贪心】【模拟】匹配
- 2016.10.29【初中部 NOIP提高组 】模拟赛C题解
- 2- noip模拟赛 DAY2
- noip模拟赛 逃避
- 2016.10.30 NOIP模拟赛 day2 AM 整理
- noip模拟赛 gcd
- 【NOIP模拟赛】Pickad 锄奸
- NOIP 模拟赛 那些年,我们学过的文化课 --致已退役的fqk神犇.
- noip模拟赛 运
- 2016.10.30 NOIP模拟赛 day2 PM 整理
- 2015.11.1 [XJOI] NOIP模拟赛总结
- NOIP模拟赛 寻找