首页 > 代码库 > UESTC1225 题解

UESTC1225 题解

题意:某公寓有N层楼,每层楼有Pi游泳爱好者和Ti个乒乓球爱好者,每层楼只能建一个游泳池或者一个乒乓球场,求所有人到其运动场所的最短距离之和(两层楼之间距离为1)

2<=N<=4000,1<=Pi,Ti<=109.1~100组数据,4000MS

题解:DP[i][j][0~1]分别表示第i层建乒乓球场,游泳场,且前一个和该处运动场所不同的位置为j,通过预处理完成O(1)转移,总复杂度为O(N2)

使用滚动数组,单独考虑来自DP[i-1][0][0~1]的转移

预处理内容:前缀和SS2[i]=S[j]*j*2(1<=j<=i),前缀和的前缀和(不必要)

 

 

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const long long inf=100000000000000000;
const int maxn=4200;
int tt,n,now;
long long t[maxn],p[maxn],sx[maxn],sy[maxn],s2x[maxn],s2y[maxn],s0x[maxn],s0y[maxn];
long long dp[2][maxn][2];
long long ans;

int main(){
    //freopen("K.in","r",stdin);
    //freopen("K.out","w",stdout);
    scanf("%d",&tt);
    for (int q=1;q<=tt;++q){
        scanf("%d",&n);
        sx[0]=0;sy[0]=0;s2x[0]=0;s2y[0]=0;s0x[0]=0;s0y[0]=0;
        for (int i=1;i<=n;++i) {scanf("%d%d",&t[i],&p[i]);sx[i]=sx[i-1]+t[i];sy[i]=sy[i-1]+p[i];s0x[i]=s0x[i-1]+sx[i];s0y[i]=s0y[i-1]+sy[i];}
        for (int i=1;i<=n;++i) {s2x[i]=s2x[i-1]+t[i]*2*i;s2y[i]=s2y[i-1]+p[i]*2*i;}
        memset(dp,0,sizeof(dp));
        now=1;
        for (int i=2;i<=n;++i){
            for (int j=1;j<=i-2;++j) dp[now][j][0]=dp[now^1][j][0]+p[i]*(i-j);
            dp[now][i-1][0]=s0x[i-1]+p[i];
            for (int j=1;j<=i-2;++j) dp[now][i-1][0]=min(dp[now][i-1][0],dp[now^1][j][1]+p[i]-(s2x[i-1]-s2x[(i-1+j)/2]-(sx[i-1]-sx[(i-1+j)/2])*(i+j)));
            for (int j=0;j<=i-2;++j) dp[now][j][1]=dp[now^1][j][1]+t[i]*(i-j);
            dp[now][i-1][1]=s0y[i-1]+t[i];
            for (int j=1;j<=i-2;++j) dp[now][i-1][1]=min(dp[now][i-1][1],dp[now^1][j][0]+t[i]-(s2y[i-1]-s2y[(i-1+j)/2]-(sy[i-1]-sy[(i-1+j)/2])*(i+j)));
            now=now^1;
        }
        now=now^1;
        ans=inf;
        for (int i=1;i<=n-1;++i) {ans=min(ans,dp[now][i][1]),ans=min(ans,dp[now][i][0]);}
        cout<<"Case #"<<q<<": "<<ans<<endl;
    }
    return 0;
}

 

UESTC1225 题解