把状态看成层,每层决策单调性处理
题目描述
题目大意
众所周知,贞鱼是一种高智商水生动物。不过他们到了陆地上智商会减半。
这不?他们遇到了大麻烦!
n只贞鱼到陆地上乘车,现在有k辆汽车可以租用。
由于贞鱼们并不能在陆地上自由行走,一辆车只能载一段连续的贞鱼。
贞鱼们互相有着深深的怨念,每一对贞鱼之间有怨气值。
第i只贞鱼与第j只贞鱼的怨气值记为Yij,且Yij=Yji,Yii=0。
每辆车载重不限,但是每一对在同辆车中的贞鱼都会产生怨气值。
当然,超级贞鱼zzp长者希望怨气值的总和最小。
不过他智商已经减半,想不出分配方案。
他现在找到了你,请你帮助他分配贞鱼们,并输出最小怨气值之和ans。
n<=4000,1 ≤ k ≤min(n , 800)
题目分析
做法一:wqs二分
这个题第一眼就像是wqs二分,并且答案函数的确是一个凸函数的形状。
于是首先是个wqs二分的模板题。
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 const int maxn = 4035; 4 const int INF = 0x3f3f3f3f; 5 6 int n,k,L,R; 7 ll a[maxn][maxn],g[maxn][maxn],f[maxn],h[maxn],ans; 8 9 char tc(){static char tr[1000000],*A=tr,*B=tr;return A==B&&(B=(A=tr)+fread(tr,1,1000000,stdin),A==B)?EOF:*A++;} 10 #define getchar tc 11 int read() 12 { 13 char ch = getchar(); 14 int num = 0, fl = 1; 15 for (; !isdigit(ch); ch=getchar()) 16 if (ch=='-') fl = -1; 17 for (; isdigit(ch); ch=getchar()) 18 num = (num<<1)+(num<<3)+ch-48; 19 return num*fl; 20 } 21 ll check(int w) 22 { 23 memset(f, 0x3f3f3f3f, sizeof f); 24 memset(h, 0x3f3f3f3f, sizeof h); 25 f[0] = h[0] = 0; 26 for (int i=1; i<=n; i++) 27 for (int j=0; j<i; j++) 28 if (f[i] > f[j]+g[j+1][i]+w||(f[i]==f[j]+g[j+1][i]+w&&h[j]+1 < h[i])){ 29 f[i] = f[j]+g[j+1][i]+w, h[i] = h[j]+1; 30 } 31 if (h[n] <= k) ans = f[n]-k*w; 32 return h[n]; 33 } 34 int main() 35 { 36 n = read(), k = read(); 37 for (int i=1; i<=n; i++) 38 for (int j=1; j<=n; j++) a[i][j] = read(); 39 for (int i=n; i>=1; i--) 40 for (int j=i; j<=n; j++) 41 g[i][j] = g[i+1][j]+g[i][j-1]-g[i+1][j-1]+a[i][j]; 42 ans = INF, L = 0, R = g[1][n]; 43 for (int mid=(L+R)>>1; L<=R; mid=(L+R)>>1) 44 if (check(mid) <= k) R = mid-1; 45 else L = mid+1; 46 printf("%lld ",ans); 47 return 0; 48 }
做法二:决策单调性
$n^2$dp是$f[j][i]$表示前$i$个鱼分为$j$组的最小代价。对于每一个同样的$j$,其转移是具有单调性的。那就是说把$i$视作层,剩下的就是层之间的转移。
暂时还没写。
END