HDU 2770 Easy Climb

首先,这题有个关键的地方就是要想到虽然它的高度很大,有10^9次方,但是实际上它的有效状态的高度只有h[i] +- k * d (k: 0 .. n-1)这么多,就是最多2*n^2个有效的高度

至于为什么是只有2*n^2的有效高度,请移步http://hi.baidu.com/sunhaowenprime/item/f7a379ba187467f663388e2d zjut_DD大牛的讲解

基于这个条件,就可以很容易得出DP状态转移方程:dp[i][j] = min(dp[i-1][k] + abs(nh[j] - h[i])), nh[]表示2*n^2个有效的离散的高度值。

然后这个用单调队列就可以将转移优化至O(1), 总时间复杂度为O(n^3)

#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(a) (a).begin(),(a).end()
#define FOR(i,a,b) for (int i=(a);i<(b);i++)
#define FORD(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,b) FOR(i,0,b)
#define sf scanf
#define pf printf
using namespace std;
const int maxint = -1u>>1;
const double pi = 3.14159265358979323;
const double eps = 1e-8;
const long long inf = 1LL << 60;
typedef pair pii;
typedef vector vi;
typedef vector::iterator vit;

int n;
long long d;
long long h[110];
inline long long ABS(long long x)
{
    return x >= 0 ? x : -x;
}
vector b;
long long dp[2][110*510];
int main() 
{
    int T;
    sf("%d", &T);
    while (T--)
    {
        sf("%d%I64d", &n, &d);
        REP(i, n) sf("%I64d", &h[i]);
        if (ABS(h[0] - h[n-1]) > 1LL * (n - 1) * d)
        {
            pf("impossible\n");
            continue;
        }
        
        b.clear();
        REP(i, n)
        {
            for (long long j = -(n-1); j <= n-1; j++) b.pb(h[i] + j * d);
        }
        
        sort(all(b));
        b.erase(unique(all(b)), b.end());
        int m = b.size(), p = 0, q;
        REP(i, m) 
            if (b[i] != h[0]) dp[p][i] = inf;
            else dp[p][i] = 0;
        FOR(i, 1, n)
        {
            q = p ^ 1;
            REP(j, m) dp[q][j] = inf;
            int k = 0;
            REP(j, m)
            {
                while (k < m && b[k] < b[j] - d) k++;
                while (k+1 < m && b[k+1] <= b[j] + d && dp[p][k+1] <= dp[p][k]) k++;
                dp[q][j] = min(dp[q][j], dp[p][k] + ABS(b[j] - h[i]));
            }
            p = q;
        }
        REP(i, m)
            if (b[i] == h[n-1])
            {
                pf("%I64d\n", dp[p][i]);
                break;
            }      
        
    }
    return 0;
}




你可能感兴趣的:(HDU,ACM)