您的位置:首页 > 其它

Easy Climb

2015-10-12 22:28 211 查看
题意:

有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
,s[MAX],dp
[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
)-s;
if(dp
[ind]>=inf)
printf("impossible\n");
else
printf("%lld\n",dp
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: