2016.7.14.2014noip模拟赛D1(网上貌似搜不到

mine:

暴力不说了

divide:

题意:把某串数分为三个部分,部分可为空。求所以三个部分的最大值中的最小值。

题解:以中间的区间为搜差部分,枚举第一个端点,二分找第二个断点。

我的错:一个是我想当然把中间当成了最大值,简直不能再脑残,应该是使第二和第三个区间尽可能接近,然后max区间1,2,3。再来个min比较上次的最大值和这次的。以及没有注意特殊情况,比如n=1,2,3

thd:

题意:

LGTB 最近在玩一个类似DOTA 的游戏名叫THD
有一天他在守一座塔,对面的N 个小兵排成一列从近到远站在塔前面
每个小兵有一定的血量hi,杀死后有一定的金钱gi
每一秒,他都可以攻击任意一个活着的小兵,对其造成P 点伤害,如果小兵的血量低于1 点,小兵死亡,他
得到金钱。他也可以不攻击任何小兵。
每一秒LGTB 攻击完毕之后,塔会攻击距离塔最近的一个活着的小兵,对其造成Q 点伤害,如果小兵的血
量低于1 点,小兵死亡,LGTB 不会得到金钱
现在LGTB 想知道,在他选择最优策略时,他能得到多少钱。

显然动规,然而我一个小时没有看出方程式。最后用动规的大致思路写了个o(n)的,过了13组。

正解:f[i][j]表示打死第i个士兵的时候,塔单独作战j次(也就是你还可以补多少次刀),的最大利益。(唉,我当时只想到j是血量,固然不知如何推论,却忘了血量可以转化为时间,事实上自己做的时候已经把血量转化为了时间,然而我的大脑并没有把这一切联系起来=-=)

代码:

#include<iostream>
#include<fstream>
using namespace std;
ifstream fin ("thd.in");
ofstream fout ("thd.out");
int h[105],P,Q,n,dataturns,myturns;
long long f[105][2002],g[105],ans;
struct stu
{
int tp,td,blood;
}a[505];
int main()
{
fin>>P>>Q>>n;
for(int i=1;i<=n;i++)
{
fin>>h[i]>>g[i];
a[i].td=(h[i]-1)/Q;
a[i].tp=(h[i]-a[i].td*Q-1)/P+1;
}

for(int i=0;i<=n;i++)
for(int j=1;j<=1002;j++)
f[i][j]=-100000000;
f[0][1]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=1002;j++)
{
if (f[i][j+a[i].td+1]<f[i-1][j])
{
f[i][j+a[i].td+1]=f[i-1][j];
}
if (j>=a[i].tp-a[i].td)
{
if (f[i][j-a[i].tp+a[i].td]<f[i-1][j]+g[i])
{
f[i][j-a[i].tp+a[i].td]=f[i-1][j]+g[i];
}
}
}
for(int i=0;i<=1002;i++)
if(f[n][i]>ans) ans=f[n][i];
fout<<ans<<endl;

return 0;
}

posted @ 2016-07-14 19:19  sci  阅读(237)  评论(0编辑  收藏  举报