調了一下午的bug終於過了。。。思路是沒錯的,可是因爲用了刷表法思考,因此只考慮刷表以後的狀態,沒有注意刷表前的最初狀態,因而調了一下午的bug終於找出來了。。。c++
dp[i][j][k] 表示 前i個,最後一個k的位置爲j ( k取0,1,j<i ) 的總花費。ide
轉移有兩個,即第i+1個位置爲0或者1:spa
dp[i+1][j][k]=min(dp[i+1][j][k] , dp[i][j][k]+a[i+1][k]*(i+1-j)) code
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的中點)blog
這裏有一點須要特別注意的是:ci
因爲過程當中不存在全0或者全1的狀況(0000或1111),因此000001不可能由00000推出來,這裏須要預處理出全部的00001和111110,也就是將dp[i][i-1][k]的初值設爲000001或1111110的值。it
另外還有一點,計算L(l,r,x,k)能夠維護一個sum(i*a[i])和sum(a[i])來實現o(1)的計算。event
#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",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\n",casen++,ans); } return 0; }