題意:輸入t組數據。每組數據輸入n,而且輸入n對數,表示這一層有a個男生,b個女生,每一層能夠修建一個宿舍,只能男生住或者女生住,求可讓這些人走的層數最少。ios
分析:首先須要保存前i層的男或女到達0的點距離和dsum,保存前i層男或女的個數sum。這樣經過這兩個數組求得一個區間內的男或女到達任一點的距離時間複雜度O(1).數組
設dp[s][i]表示計算到第i個且將其放在該段的最後一個,這一段全爲s(0和1分別表示兩種運動)那麼dp方程就是dp[s][i] = min{dp[s^1][j] + valueSum(j+1, i)}, j < ispa
valueSum(i, j)表示[i, j]區間內的員工到最近運動室的距離和。code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #include <cstdlib> #include <map> using namespace std; const int maxn = 4005; long long a[maxn], b[maxn]; long long dp[2][maxn];//dp[sex][i]表示第i層樓的寢室屬性爲sex,第i+1層寢室屬性不爲sex條件下,前i層樓去寢室至少須要的距離之和 long long sum[2][maxn]; long long dsum[2][maxn]; long long goup(int sex, int l, int r)//區間[l+1, r]的sex人到r+1的距離 { return (sum[sex][r]-sum[sex][l])*(r+1) - (dsum[sex][r]-dsum[sex][l]); } long long godown(int sex, int l, int r)//區間[l+1, r]的sex人到l的距離 { return (dsum[sex][r]-dsum[sex][l]) - (sum[sex][r]-sum[sex][l])*l; } long long cnt(int sex, int l, int r)//區間[l+1, r]區間的sex人到l或者r+1的最短距離 { int mid = (l+r)/2; return goup(sex, mid, r)+godown(sex, l, mid); } int main() { int t, n; scanf("%d", &t); int tt = 1; while(t--) { scanf("%d", &n); sum[0][0] = sum[0][1] = 0; for(int i=1; i<=n; i++) { scanf("%lld %lld", &a[i], &b[i]); sum[0][i] = sum[0][i-1] + a[i]; sum[1][i] = sum[1][i-1] + b[i]; dsum[0][i] = dsum[0][i-1] + a[i]*i; dsum[1][i] = dsum[1][i-1] + b[i]*i; } long long ans = 1e18; for(int i=1; i<n; i++) { dp[0][i] = goup(1, 0, i);//1~i層爲0,第i+1層爲1,[1, i+1]層的人所要花費的距離 dp[1][i] = goup(0, 0, i);//1~i層爲1,第i+1層爲0,[1, i+1]層的人所要花費的距離 for(int j=1; j<i; j++) { dp[0][i] = min(dp[0][i], dp[1][j]+cnt(1, j, i));//枚舉[j, i]層sex爲0, 更新[1, i+1]層的人花費的距離最小值 dp[1][i] = min(dp[1][i], dp[0][j]+cnt(0, j, i));//枚舉[j, i]層sex爲1, 更新[1, i+1]層的人花費的距離最小值 } ans = min(ans, dp[0][i]+godown(0, i, n));//第i層sex爲0前i層最優解加上[i+1, n]sex爲0的人到達i層花費最短距離 ans = min(ans, dp[1][i]+godown(1, i, n));//第i層sex爲1前i層最優解加上[i+1, n]sex爲1的人到達i層花費最短距離 } printf("Case #%d: %lld\n", tt++, ans); } return 0; }