DP+滚动数组 || [Usaco2007 Nov]Telephone Wire 架设电话线 || BZOJ 1705 || Luogu P2885
本来是懒得写题解的…想想还是要勤发题解和学习笔记…然后就滚过来写题解了。
题面:[USACO07NOV]电话线Telephone Wire
题解:
F[ i ][ j ] 表示前 i 根电线杆,第 i 根电线杆长度为 j 时的最优答案
容易推出基本的转移方程:
mx为初始最长的电线杆长度,显然延长后的电线杆最长不会超过mx
然后就把绝对值拆开,分类讨论一下
然后就发现这个东西可以单调队列优化DP,但是这个题目并不需要单队优化,在循环时记录一下最大值就可以
然后因为给的空间就64MB,所以要套一个滚动数组
就这样了…啊写题解好累啊
代码:
1 #include<cstdio> 2 #define max(a,b) ((a)>(b)?(a):(b)) 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 #define sqr(a) ((a)*(a)) 5 using namespace std; 6 const int maxn=1e5+5,inf=1<<30,maxh=105; 7 int N,C,H[maxn],F[2][maxh],mx=0,ans=inf; 8 int main(){ 9 scanf("%d%d",&N,&C); 10 for(int i=1;i<=N;i++) scanf("%d",&H[i]),mx=max(mx,H[i]); 11 for(int i=0;i<=mx;i++) F[0][i]=F[1][i]=inf; 12 for(int i=H[1];i<=mx;i++) F[1][i]=sqr(i-H[1]); 13 for(int i=2;i<=N;i++){ 14 int k=inf; 15 for(int j=H[i-1];j<=mx;j++){ 16 k=min(k,F[(i-1)&1][j]-C*j); 17 if(j>=H[i]) F[i&1][j]=k+j*C+sqr(j-H[i]); 18 } 19 k=inf; 20 for(int j=mx;j>=H[i];j--){// 21 k=min(k,F[(i-1)&1][j]+C*j); 22 F[i&1][j]=min(F[i&1][j],k-j*C+sqr(j-H[i])); 23 } 24 for(int j=0;j<=mx;j++) F[(i+1)&1][j]=inf; 25 } 26 for(int i=H[N];i<=mx;i++) ans=min(ans,F[N&1][i]); 27 printf("%d\n",ans); 28 return 0; 29 }
By:AlenaNuna