[BZOJ1617]跨河crossing the river

来源:互联网 发布:网络大电影项目书 编辑:程序博客网 时间:2024/04/29 08:39

我们先说一个一定会超时的做法

dp[i][j]表示前i头牛用了j个来回来转移

枚举k表示从i-k(还是i-k+1?)到i的牛由本次来转移

dp[i][j]=min(dp[i][j],dp[i-k][j-1]+sum[i-k]+m*2)

最后答案就是dp[n][0……n]里的最大值。

这样肯定会超时,我们考虑j

j其实并没有对我们的式子做出任何贡献,换言之,他只是让我们的转移条件更严格,但是花费了大量的时间复杂度。

因此我们发现这个题是线性的。

dp[i]表示前i头牛的转移最小时间

dp[i]=min(dp[i],dp[i-k]+sum[i-k]+2*m)

最后答案就是dp[n]-m

为什么这样是对的?

我们在第一次转移的时候就能看出来j其实并没有任何用处。

为什么?

dp[i][j]是前i头牛用了j个来回转移,但是我们已经记录了最优值了,我们为什么还要在乎用了几个来回转移?

换言之,我们不关心到底之前用了几个来回,我们只关心牛用了多少,子问题是这一次和上一次的牛,而不是来回数。

这样,这个题就做完了

/*One Night Of The Hunters*/#include<cstdio>#include<cstdlib>#include<iostream>#include<cstring>#include<algorithm>#include<queue>#include<iomanip>#include<stack>#include<map>#include<set>#include<cmath>#define debug(x) cerr<<#x<<"="<<x<<endl#define INF 0x7f7f7f7f#define llINF 0x7fffffffffusing namespace std;typedef pair<int,int> pii;typedef long long ll;inline int init(){    int now=0,ju=1;char c;bool flag=false;    while(1)    {        c=getchar();        if(c=='-')ju=-1;        else if(c>='0'&&c<='9')        {            now=now*10+c-'0';            flag=true;        }        else if(flag)return now*ju;    }}inline long long llinit(){    long long now=0,ju=1;char c;bool flag=false;    while(1)    {        c=getchar();        if(c=='-')ju=-1;        else if(c>='0'&&c<='9')        {            now=now*10+c-'0';            flag=true;        }        else if(flag)return now*ju;    }}int dp[2550];int sum[2550];int m;int n;int a[2550];int main(){n=init();m=init();memset(dp,0x7f,sizeof(dp));for(int i=1;i<=n;i++){a[i]=init();sum[i]=sum[i-1]+a[i];}dp[0]=0;for(int i=1;i<=n;i++){for(int j=0;j<i;j++){dp[i]=min(dp[i],dp[j]+sum[i-j]+m*2);}}printf("%d\n",dp[n]-m);return 0;}


0 0