hdu3851.Beat It!
来源:互联网 发布:奥点云 vs 阿里云 编辑:程序博客网 时间:2024/05/12 04:40
http://acm.hdu.edu.cn/showproblem.php?pid=3851
题意:有一只怪兽,在白天攻击一次能损失它pd点血,晚上攻击则损失它pn点血,每次攻击的间隔为t,每天的白天时间与晚上时间分别为t1i, t2i,问N天内最多攻击它多少血。n <= 1000, t <= 100
思路:dp,先把问题等价为n×2段,每段的价值为相应的pd或者为pn,不妨都记为pi,显然每次记录一个时间段最后t时间的攻击状况即可,f[i][j]表示第i个时间段最后一次攻击在第tt[i]-j的最优值,则转移方程为
f[i][j] = max{ g[p[i][j]] + ((tt[i] - j - 1)/t+1) * pi), h[p[i][j]+1][k] + ((tt[i] - j - 1) / t + 1), g[i - 1] + ((tt[i] - j - 1) / t) };
其中,g[i]为前i段所有情况中最优的结果,p[i][j]=max{p`| tt[p` + 1] + tt[p` + 2] + ... + tt[i - 1] + (tt[i] - j - 1) % t >= t }, k满足k + tt[p + 2] + tt[p + 3] + ... + tt[i - 1] + (tt[i] - j - 1) % t = t,h[p][k] = max{ f[p][k], f[p][k + 1], ... , f[p][t - 1]}
这个方程的意思是找以下情况中最大的
(1) 前p段最大的,然后满足tt[p + 1] + tt[p + 2] + ... + tt[i - 1] + (tt[i] - j - 1) % t >= t, 所以在第i段从任意点开始攻击,最多攻击((tt[i] - j - 1)/t+1)次;
(2) 在第p+1段,最后, 最后一次攻击在第k次,因为 k满足k + tt[p + 2] + tt[p + 3] + ... + tt[i - 1] + (tt[i] - j - 1) % t = t, 所以同理在第i段从任意点开始攻击,最多攻击((tt[i] - j - 1)/t+1)次;
(3) 在第i段放少一个,那么必然可以使得第一段末尾至少可以空出t-1的时间点出来,也就肯定不会跟第i-1的时间段的攻击产生冲突。
列好方程之后首先预处理出p和k,
因为如果固定最后攻击的时间,固定次数(最大可能情况), 那么肯定尽可能放在后面攻击,所以如果对于这样的一个固定的区间,最迟第一次攻击可以在区间(tt[i] - j - 1) % t 后,而且,显然(tt[i] - j1 - 1) % t > (tt[i] - j2 - 1) % 2, p[i][j1] > p[i][j2], 所以先在线性时间内求出所以t2[r], 则p[i][j] = t2[(tt[i] - j - 1) % t ];
k = t - (tt[p + 2] + tt[p + 3] + ... + tt[i - 1] + (tt[i] - j - 1) % t)。
此时转移时间在预处理之后能在O(1)时间内完成,最后时间复杂度为O(nt).
其实若t = 1, pn = pd = 2 ^ 31 - 1, tt[i] = 2 ^ 31. 那么答案应该会超出long long的范围,不过我尝试不写高精度过了。
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define sqr(x) ((x) * (x))#define two(x) (1 << (x))#define Rep(i, s, n) for (int i = s; i < (n); ++i)#define X first#define Y secondtypedef long long LL;const int MAXN = 2012;const double eps = 1e-9;const int INF = 1000000000;int n, t, pn, pd, tt[MAXN];LL f[MAXN][200], g[MAXN], ss[MAXN];int pre[MAXN][200], tmp[200];void init(){ scanf("%d%d%d%d", &n, &t, &pd, &pn); Rep(i, 0, 2 * n) scanf("%d", &tt[i + 1]); ss[0] = 0; Rep(i, 0, 2 * n) ss[i + 1] = ss[i] + tt[i + 1]; Rep(i, 1, 2 * n + 1) { tmp[0] = 0; Rep(j, 0, i) if (ss[i - 1] - ss[i - j - 1] >= t) { tmp[0] = i - j - 1; break; } Rep(j, 1, min(t, tt[i])) { tmp[j] = tmp[j - 1]; while (ss[i - 1] - ss[tmp[j] + 1] + j >= t) ++tmp[j]; } int rem = tt[i] % t; Rep(j, 0, min(t, tt[i])) { rem = (rem + t - 1) % t; pre[i][j] = tmp[rem]; } }}void work(){ g[0] = 0; Rep(i, 1, n * 2 + 1) { LL pt = ((i & 1)? pd: pn); Rep(j, 0, min(t, tt[i])) { f[i][j] = g[pre[i][j]] + pt * ((tt[i] - j - 1) / t + 1); int rem = (tt[i] - j - 1) % t; if (rem + ss[i - 1] >= t) f[i][j] = max(f[i][j], f[pre[i][j] + 1][t - 1 - rem] + pt * ((tt[i] - j - 1) / t + 1)); if (tt[i] - j - 1 >= t) f[i][j] = max(f[i][j], g[i - 1] + pt * ((tt[i] - j - 1) / t)); } Rep(j, 1, min(t, tt[i])) { f[i][min(t, tt[i]) - j - 1] = max(f[i][min(t, tt[i]) - j - 1], f[i][min(t, tt[i]) - j]); } g[i] = max(g[i - 1], f[i][0]); } cout << g[n * 2] << endl;}int main(){ int T, ca = 0; scanf("%d", &T); while (T--) { printf("Case %d: ", ++ca); init(); work(); } return 0;}
然后看着今天上海的board,觉得自己没去好幸福……
- hdu3851.Beat It!
- hdu3851
- hdu 3581 Beat It!
- BUPT 199 Beat it!
- Beat
- Beat
- Beat
- Beat
- Beat
- HDOJ Beat
- HDU2614 Beat
- HDU2614 Beat
- 第一次出击(first beat)
- [组图]Ubuntu BEAT Federa!!!
- Beat the Spread!
- Beat a retreat 打退堂鼓
- 打败自我-----"Beat youself"
- Can C beat RTL?
- 程序员技术练级攻略
- 创建lv 报空间不足 lsvg -p vg_name 是有pp (第二篇)
- poj 2886 Who Gets the Most Candies?
- VS2008 打开VS2010解决方案及项目
- 最小编辑距离的理解
- hdu3851.Beat It!
- Java开发环境搭建
- 编写苹果游戏中心应用程序(翻译 1.5 在游戏中心验证本地玩家)
- LS代理中调用方法并且得到返回值
- Joomla! (DAY 9) - Joomsport (DAY 7): Create a Real View 'Home VS Away'
- 我对架构的理解-概念篇
- 二、Python:控制结构
- sed命令的备注
- 排序 2 选择排序