HOJ 魔法少女Clara的快乐训练(名字是自己编的,因为看不到原题的名字QWQ) dp

题意概述:

多组测试。Clara在N天中至多选择M天进行训练,每天题目的难度为ci,Clara初始实力值为0。现在假如第i天正常训练,那么假设当前实力值为x,当天题目难度为y。

当y

当x-100<=y<=x,Clara实力值加一(锻炼了手速)

当x

当y>x+100,Clara实力值增加5000/(y-x),向下取整(成功或者失败地突破了极限)

现在大仙Claris被Clara感动了,决定可以在N天中选择连续的3天对Clara进行特训(这三天算在M天中),若特训前实力值不超过2148473547,则特训后实力值增加100,否则实力值增加99。

问N天后Clara实力值最大是多少。

数据范围:最多10组数据,1 <= m <= n <= 3000,0 <= Ci <= 1e8,Time limit : 5 sMemory limit : 512 mb

 

分析:

想想我开始强行写BFS爆搜还剪枝的操作,挺迷的……因为这个题就长了一张dp的脸啊QWQ,一开始没有拨开题目的包装导致没有找到最优子结构的形式,以为不能dp。

 

首先分析实力值的变化,把不等式变形一下,变成x>y+100, y<=x<=y+100, y-100<=x变化的应该是x,所以把x写在由y确定的区间里面)。然后分析一下这几个不等式的几句话,有几个重要的信息藏在里面:

1.最优方案中,摸鱼导致实力值变成0的情况不能发生,突破极限失败的情况也不可以发生,也就是说实力值应当是单调递增的。

2.实力值每次最多增加50,那么N天后实力值最大为150000,显然每次Claris给Clara特训的时候实力值都是增加100。

3.若x

   若y-100<=x

   若y<=x<=y+100,那么训练后x落在[y+1,y+101]

   也就是说,假如当前实力值x在第i天不会摸鱼,那么实力值x越大,第i天训练后实力值越大。

4.假设前i天最大实力值是x,对于第j天 ( j>i ) ,x>y+100,那么任何第j天进行训练的方案训练后的实力值都不可能比x大。

 

根据上面的分析,已经可以构思dp方程了。

定义:设f(n,m,0/1)表示前n天,至少训练m天,是否有进行过特殊训练,的最大实力值。

转移:考虑f(n,m,0)。第n天不训练,则从f(n-1,m,0)转移。

                                  第n天训练(伪),那么若f(n-1,m-1,0)>c[n]+100,从f(n-1,m-1,0)直接转移;否则对实力值f(n-1,m-1,0)在第n天进行训练,转移。

           考虑f(n,m,1)。第n天不训练和一般训练同上,对于特殊训练,保证下标有意义的情况下转移即可。

答案:MAX( f(N,M,0) , f(N,M,1) )

边界:f(0,0,0)=0,注意f中第一维时刻不小于第二维(这也是粗体字下划线部分必要的原因)

时间复杂度:O(NM)

 

AC代码:

 1 #include
 2 #include<string.h>
 3 #include
 4 #define maxn 3005
 5 #define inf 1e8
 6 
 7 int T,N,M,C[maxn];
 8 int f[maxn][maxn][2];
 9 
10 int Min(int x,int y){ return xx:y; }
11 int Max(int x,int y){ return x>y?x:y; }
12 
13 void data_in()
14 {
15     scanf("%d%d",&N,&M);
16     for(int i=1;i<=N;i++)
17         scanf("%d",&C[i]);
18 }
19 int g(int x,int n)
20 {
21     if(x-100<=C[n]&&C[n]<=x) return x+1;
22     if(x100) return x+(C[n]-x+1)/2;
23     if(C[n]>x+100) return x+5000/(C[n]-x);
24     return 0;
25 }
26 void dp()
27 {
28     memset(f,0,sizeof(f));
29     for(int i=1;i<=N;i++){
30         int U=Min(i,M);
31         for(int j=1;j<=U;j++){
32             int tmp=-inf;
33             if(i-1>=j) tmp=f[i-1][j][0];
34             if(f[i-1][j-1][0]>C[i]+100) tmp=Max(tmp,f[i-1][j-1][0]);
35             else tmp=Max(tmp,g(f[i-1][j-1][0],i));
36             f[i][j][0]=tmp;
37             
38             tmp=-inf;
39             if(i-1>=j) tmp=f[i-1][j][1];
40             if(f[i-1][j-1][1]>C[i]+100) tmp=Max(tmp,f[i-1][j-1][1]);
41             else tmp=Max(tmp,g(f[i-1][j-1][1],i));
42             if(i>=3&&j>=3) tmp=Max(tmp,f[i-3][j-3][0]+100);
43             f[i][j][1]=tmp;
44         }
45     }
46 }
47 void work()
48 {
49     dp();
50     int ans=Max(f[N][M][0],f[N][M][1]);
51     printf("%d\n",ans);
52 }
53 int main()
54 {
55     freopen("test.in","r",stdin);
56     freopen("test.out","w",stdout);
57     scanf("%d",&T);
58     for(int t=1;t<=T;t++){
59         printf("Case #%d: ",t);
60         data_in();
61         work();
62     }
63     return 0;
64 }
View Code

 

你可能感兴趣的:(HOJ 魔法少女Clara的快乐训练(名字是自己编的,因为看不到原题的名字QWQ) dp)