hdu5550 Game Rooms dp

hdu5550 Game Rooms  dp

调了一下午的bug终于过了。。。思路是没错的,但是由于用了刷表法思考,所以只考虑刷表之后的状态,没有注意刷表前的最初状态,于是调了一下午的bug终于找出来了。。。

dp[i][j][k] 表示 前i个,最后一个k的位置为j ( k取0,1,j<i ) 的总花费。

转移有两个,即第i+1个位置为0或者1:

dp[i+1][j][k]=min(dp[i+1][j][k] , dp[i][j][k]+a[i+1][k]*(i+1-j)) 

dp[i+1][i][!k]=min(dp[i+1][i][!k],  dp[i][j][k]+L(j+1,m,j,k)+L(m+1,i,i+1,k)-L(j+1,i,j,k)+a[i+1][!k])  (m为j和i+1的中点)

这里有一点需要特别注意的是:

由于过程中不存在全0或者全1的情况(0000或1111),所以000001不可能由00000推出来,这里需要预处理出所有的00001和111110,也就是将dp[i][i-1][k]的初值设为000001或1111110的值。

另外还有一点,计算L(l,r,x,k)可以维护一个sum(i*a[i])和sum(a[i])来实现o(1)的计算。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=4010;
const int INF=1<<29;

int n;
ll a[maxn][2],s[maxn][2],fs[maxn][2];
ll si[maxn][2],fsi[maxn][2];
ll dp[2][maxn][2];

ll Pre(int l,int r,int x,int k)
{
    if(l>r) return 0;
    return (si[r][k]-si[l-1][k])-(s[r][k]-s[l-1][k])*x;
}

ll Suf(int l,int r,int x,int k)
{
    if(l>r) return 0;
    return (fsi[l][k]-fsi[r+1][k])-(fs[l][k]-fs[r+1][k])*(n-x+1);
}

ll L(int l,int r,int x,int k)
{
    if(l>r) return 0;
    if(x<=l) return Pre(l,r,x,k);
    if(x>=r) return Suf(l,r,x,k);
    return Suf(l,x-1,x,k)+Pre(x+1,r,x,k);
}

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int T;cin>>T;int casen=1;
    while(T--){
        scanf("%d",&n);
        REP(i,1,n) scanf("%I64d%I64d",&a[i][0],&a[i][1]);
        //out();
        s[0][0]=s[0][1]=0;
        si[0][0]=si[0][1]=0;
        REP(i,1,n){
            s[i][0]=s[i-1][0]+a[i][0];
            s[i][1]=s[i-1][1]+a[i][1];
            si[i][0]=si[i-1][0]+a[i][0]*i;
            si[i][1]=si[i-1][1]+a[i][1]*i;
        }
        fs[n+1][0]=fs[n+1][1]=0;
        fsi[n+1][0]=fsi[n+1][1]=0;
        for(int i=n;i>=1;i--){
            fs[i][0]=fs[i+1][0]+a[i][0];
            fs[i][1]=fs[i+1][1]+a[i][1];
            fsi[i][0]=fsi[i+1][0]+a[i][0]*(n-i+1);
            fsi[i][1]=fsi[i+1][1]+a[i][1]*(n-i+1);
        }
        MS0(dp);
        ll MAX=1LL<<60;
        memset(dp,0x3f3f3f,sizeof(dp));
        ll ans=MAX;
        dp[2%2][1][0]=a[1][1]+a[2][0];
        dp[2%2][1][1]=a[1][0]+a[2][1];
        REP(i,2,n-1){
            REP(j,1,i){
                REP(k,0,1){
                    dp[(i+1)%2][j][k]=L(1,j,j+1,!k)+L(j+1,i+1,j,k);
                }
            }
            REP(j,1,i-1){
                REP(k,0,1){
                    dp[(i+1)%2][j][k]=min(dp[(i+1)%2][j][k],dp[i%2][j][k]+a[i+1][k]*(i+1-j));
                    int m=(j+i+1)>>1;
                    dp[(i+1)%2][i][!k]=min(dp[(i+1)%2][i][!k],dp[i%2][j][k]+L(j+1,m,j,k)+L(m+1,i,i+1,k)-L(j+1,i,j,k)+a[i+1][!k]);
                }
            }
        }
        REP(i,1,n-1){
            //printf("dp[%d][%d][0]=%I64d dp[%d][%d][1]=%I64d
",n,i,dp[n%2][i][0],n,i,dp[n%2][i][1]);
            ans=min(ans,dp[n%2][i][0]);
            ans=min(ans,dp[n%2][i][1]);
        }
        printf("Case #%d: %I64d
",casen++,ans);
    }
    return 0;
}
View Code
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/5070223.html