[USACO08FEB]修路Making the Grade
比较难的dp,比赛时打的找LIS,然后其他的尽可能靠近,40分。
先举个例子
6
1 2 3 1 4 5
6
1 2 3 3 4 5
第4个1要么改成3,要么改成4,反正是数列中的数。
所以最优情况下,答案中的数都是原数列中有的。
b[]是a[]由小到大排序之后的数组
令f[i][j]表示使前i个数成为不减的最小花费,而且第i个的高度为b[j].
f[i][j]=min(f[i-1][k])+abs(a[i]-b[j]);1<=k<=n
k从1~n递增,一个显然的优化就是单调队列,递增的,每次取队首。
不增同理。
AC:
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<cmath> #include<ctime> #include<cstring> #define inf 2147483647 #define For(i,a,b) for(register int i=a;i<=b;i++) #define p(a) putchar(a) #define g() getchar() //by war //2017.10.18 using namespace std; int f[2010][2010]; int q[2010]; int a[2010]; int b[2010]; int l,r; int ans; int n; int m; void in(int &x) { int y=1; char c=g();x=0; while(c<'0'||c>'9') { if(c=='-') y=-1; c=g(); } while(c<='9'&&c>='0')x=x*10+c-'0',c=g(); x*=y; } void o(int x) { if(x<0) { p('-'); x=-x; } if(x>9)o(x/10); p(x%10+'0'); } int main() { in(n); For(i,1,n) in(a[i]),b[i]=a[i]; sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1; For(i,1,n) { r=0; For(j,1,m) { while(r&&f[i-1][j]<=f[i-1][q[r]])r--; q[++r]=j; f[i][j]=f[i-1][q[1]]+abs(a[i]-b[j]); } } ans=inf; For(i,1,m) ans=min(ans,f[n][i]); For(i,1,n) For(j,1,n) f[i][j]=0; For(i,1,n) { r=0; For(j,1,m) { while(l<=r&&f[i-1][j]>=f[i-1][q[r]])r--; q[++r]=j; f[i][j]=f[i-1][q[1]]+abs(a[i]-b[m]); } } ans=min(ans,f[n][m]); o(ans); return 0; }
考场贪心骗分代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 #include<cmath> 6 #include<ctime> 7 #include<cstring> 8 #define inf 2147483647 9 #define For(i,a,b) for(register int i=a;i<=b;i++) 10 #define p(a) putchar(a) 11 #define g() getchar() 12 //by war 13 //2017.10.18 14 using namespace std; 15 int n; 16 int Max; 17 int last; 18 int a[2010]; 19 int d[2010]; 20 bool b[2010]; 21 int p[2010]; 22 int f[2010]; 23 int ans[5]; 24 void in(int &x) 25 { 26 int y=1; 27 char c=g();x=0; 28 while(c<'0'||c>'9') 29 { 30 if(c=='-') 31 y=-1; 32 c=g(); 33 } 34 while(c<='9'&&c>='0')x=x*10+c-'0',c=g(); 35 x*=y; 36 } 37 void o(int x) 38 { 39 if(x<0) 40 { 41 p('-'); 42 x=-x; 43 } 44 if(x>9)o(x/10); 45 p(x%10+'0'); 46 } 47 48 void LIS() 49 { 50 For(i,1,n) 51 f[i]=1,d[i]=0; 52 For(i,1,n) 53 { 54 For(j,1,i-1) 55 { 56 if(a[j]<=a[i]) 57 { 58 if(f[j]+1>f[i]) 59 { 60 f[i]=f[j]+1; 61 d[i]=j; 62 } 63 } 64 } 65 if(Max<f[i]) 66 { 67 Max=f[i]; 68 last=i; 69 } 70 } 71 int ft; 72 for(ft=last;d[ft]!=0;ft=d[ft]) 73 b[ft]=true; 74 for(int i=ft-1;i>=1;i--) 75 { 76 ans[0]+=abs(p[i]-p[i+1]); 77 p[i]=p[i+1]; 78 } 79 For(i,ft+1,n) 80 if(!b[i]) 81 { 82 ans[0]+=abs(p[i]-p[i-1]); 83 p[i]=p[i-1]; 84 } 85 } 86 87 void LRS() 88 { 89 Max=0; 90 For(i,1,n) 91 f[i]=1,b[i]=false,d[i]=0; 92 For(i,1,n) 93 { 94 For(j,1,i-1) 95 { 96 if(a[j]>=a[i]) 97 { 98 if(f[j]+1>f[i]) 99 { 100 f[i]=f[j]+1; 101 d[i]=j; 102 } 103 } 104 } 105 if(Max<f[i]) 106 { 107 Max=f[i]; 108 last=i; 109 } 110 } 111 int ft; 112 for(ft=last;d[ft]!=0;ft=d[ft]) 113 b[ft]=true; 114 for(int i=ft-1;i>=1;i--) 115 { 116 ans[1]+=abs(p[i]-p[i+1]); 117 p[i]=p[i+1]; 118 } 119 For(i,ft+1,n) 120 if(!b[i]) 121 { 122 ans[1]+=abs(p[i]-p[i-1]); 123 p[i]=p[i-1]; 124 } 125 } 126 127 int main() 128 { 129 // freopen("grading.in","r",stdin); 130 // freopen("grading.out","w",stdout); 131 in(n); 132 For(i,1,n) 133 in(a[i]),p[i]=a[i]; 134 LIS(); 135 For(i,1,n) 136 p[i]=a[i]; 137 LRS(); 138 o(min(ans[0],ans[1])); 139 return 0; 140 }