标签:
题意:
有n块石头,给定他们的高度,现保持第一和最后一块高度不变,其他可增加和减少高度,求通过变换使所有相邻石头的高度差的绝对值不大于d,所变化高度总和的最小值。
分析:
状态还可以想出来,dp[i][j]=min(dp[i-1][k])+abs(s[j]-h[i]),j,k表示i,i-1高度的状态,h[i]为初始高度。但高度太大,高度状态太多,没法下手,看过题解才知道,所有可能的高度状态有hi+kd(1<=i<=n,-n<k<n)种,现在理解的还不透,就可以把状态离散化,再递推就行了,开始可能min(dp[i-1][k])没求好,一直TE。
#include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <string> #include <cctype> #include <complex> #include <cassert> #include <utility> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const long long inf=1LL<<62; const int N=110; const int MAX=N*N*2; int n,num; long long h[N],s[MAX],dp[N][MAX],d; int q[MAX]; void solve() { for(int i=0;i<=n;i++) for(int j=0;j<num;j++) dp[i][j]=inf; int ind=lower_bound(s,s+num,h[1])-s; dp[1][ind]=0; for(int i=2;i<=n;i++) { int pre=0,last=0,now=0; for(int j=0;j<num;j++) { while(now<num&&s[now]<=s[j]+d) { while(pre<last&&dp[i-1][q[last-1]]>=dp[i-1][now]) last--; q[last++]=now++; } while(pre<last&&s[j]-d>s[q[pre]]) pre++; dp[i][j]=abs(h[i]-s[j])+dp[i-1][q[pre]]; } } ind=lower_bound(s,s+num,h[n])-s; if(dp[n][ind]>=inf) printf("impossible\n"); else printf("%lld\n",dp[n][ind]); } int main() { int T; scanf("%d",&T); while(T--) { num=0; scanf("%d%lld",&n,&d); for(int i=1;i<=n;i++) scanf("%lld",&h[i]); for(int i=1;i<=n;i++) for(long long j=0;j<n;j++) { s[num++]=h[i]-j*d; s[num++]=h[i]+j*d; } sort(s,s+num); num=unique(s,s+num)-s; solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/zsf123/p/4873076.html