题意:输入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; }