最近考了个叫做NOIP模拟的题。。。。。
真是难以吐槽。NOIP怎么考到了自动机去了。。。。。
当然,想我这种蒟蒻就只能膜拜机房里的各位大牛了。。。。
不管怎么说,我们来看一下这道很厉害的DP。
题目大意:
给定 N 个数, 请你将他们分成两组, 并使得两组的代价和最少
(每一组的代价定义为 ∑¦Hpi-1 - Hpi¦, pi-1 < pi)
我考场上只想到了 20 分的DP:令 f[i][j][k] 表示 考虑前 i 个 两组结尾分别为 j , k 时的最优值。
考试后,大牛就给了我一个 50 分算法:f[i][j] 表示 第一列以 i 结尾, 第二列以 j 结尾的最优值。(强制令 i > j)
那么很明显 f[i][j] -> f[i+1][i] 或 f[i+1][j]
:-( 怎么会这样呢?
第二天,大牛告诉我说他 AC 了, 一问才知道 他强制令 i - j <= 20 这样居然骗到了 95 分。。。(⊙o⊙)…
没办法,自己怎么会有那么厉害的YY能力?
只能看题解:
所以说不愧是题解
令 g[i] = f[i][i-1]
则 g[i] = min(g[j] + sum[i-1] - sum[j] + abs(H[i] - H[j-1])) (sum[i] = sum[i-1] + abs(Hi - Hi-1))
那么我们对这个绝对值号进行分类讨论,那么就可以维护处最优解了。
我们用两棵树状数组来维护这个值 (即 g[j] - sum[j] ± H[j-1])
我们先将 H[i] 离散化, 那么对于 H[i] > H[j] 查找的范围为 树状数组A [1 , i)
否则为 树状数组B (i, n]
代码就是这个样子的:
1 #include<cstdlib> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define maxn 500500 6 using namespace std; 7 long long n,h[maxn]; 8 long long sum[maxn]; 9 long long Bit1[maxn],Bit2[maxn]; 10 long long f[maxn]; 11 long long ans,a[maxn],tot; 12 int lowbit(int x) 13 { 14 return x & (-x); 15 } 16 void change(long long bit[],int pos,long long x) 17 { 18 while(pos <= n){ 19 bit[pos] = min(bit[pos],x); 20 pos += lowbit(pos); 21 } 22 } 23 long long ask(long long bit[],int pos) 24 { 25 long long ret = 0x7fffffffff; 26 while(pos){ 27 ret = min(ret,bit[pos]); 28 pos -= lowbit(pos); 29 } 30 return ret; 31 } 32 int main() 33 { 34 freopen("sprung.in","r",stdin); 35 freopen("sprung.out","w",stdout); 36 scanf("%I64d",&n); 37 memset(Bit1,0x3f,sizeof(Bit1)); 38 memset(Bit2,0x3f,sizeof(Bit2)); 39 f[0] = 0; 40 ans = 0x7ffffffff; 41 for(int i=1;i<=n;++i) scanf("%I64d",&h[i]),a[i] = h[i]; 42 sort(a+1,a+n+1); tot = unique(a+1,a+n+1) - a; 43 for(int i=1;i<=n;++i) sum[i] = sum[i-1] + abs(h[i] - h[i-1]); 44 change(Bit1,1,0); 45 change(Bit2,tot,0); 46 for(int i=2;i<=n;++i){ 47 int pos = lower_bound(a+1,a+tot,h[i]) - a + 1; 48 long long x1 = ask(Bit1,pos) + h[i] ; 49 long long x2 = ask(Bit2,tot - pos + 1) - h[i]; 50 f[i] = min(x1,x2) + sum[i-1]; 51 ans = min(ans,f[i] + sum[n] -sum[i]); 52 pos = lower_bound(a+1,a+tot,h[i-1]) - a + 1; 53 change(Bit1,pos,f[i] - sum[i] - h[i-1]); 54 change(Bit2,tot - pos + 1,f[i] - sum[i] + h[i-1]); 55 } 56 printf("%I64d",ans); 57 return 0; 58 }