BZOJ1705: [Usaco2007 Nov]Telephone Wire 架设电话线
n<=100000个杆,给高度,增加高度代价为增加量的平方,通过增加使得sigma (a[i]-a[i-1])*C,2<=i<=n的值最小。
f[i][j]--前i根杆第i根高度j的最大值,f[i][j]=min(f[i-1][k]+C*|k-j|+(j-a[i])2),过不了。
把绝对值拆掉,就有个只跟k有关的部分和只跟j有关的部分,一个用前缀转移一个用后缀转移即可。有点抽象,自行拆绝对值看。
转移时注意定义域!
于是WA了一发,原因:最后一句<=100写成<=n。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<math.h> 5 //#include<iostream> 6 using namespace std; 7 8 int n,C; 9 #define maxn 100011 10 int a[maxn];int f[111],mx[111]; 11 int sqr(int x) {return x*x;} 12 const int inf=0x3f3f3f3f; 13 int main() 14 { 15 scanf("%d%d",&n,&C); 16 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 17 for (int i=0;i<a[1];i++) f[i]=inf; 18 for (int i=a[1];i<=100;i++) f[i]=sqr(a[1]-i); 19 for (int i=2;i<=n;i++) 20 { 21 mx[100]=f[100]+C*100; 22 for (int j=99;j>=0;j--) mx[j]=min(mx[j+1],f[j]+C*j); 23 int Min=inf; 24 for (int j=a[i-1];j<a[i];j++) Min=min(Min,f[j]-C*j); 25 for (int j=0;j<a[i];j++) f[j]=inf; 26 for (int j=a[i];j<=100;j++) 27 { 28 Min=min(Min,f[j]-C*j); 29 f[j]=min(Min+C*j,mx[j]-C*j)+sqr(j-a[i]); 30 } 31 } 32 int ans=inf; 33 for (int i=0;i<=100;i++) ans=min(ans,f[i]); 34 printf("%d\n",ans); 35 return 0; 36 }