HDU5945 Fxx and game

题目大意:一开始你将会得到一个数X(1X106) ,每次游戏将给定两个参数k,t(1k,t106) , 任意时刻你可以对你的数执行下面两个步骤之一:

1.X=Xi(1it)

2.若Xk 的倍数,X=X/k

保证有解,求X变成1的最小步数。

题解:容易想到一个dp,dp[i] 表示数字i 需要的最少步数。那么转移为dp[i]=min(min1jt(dp[ij]),dp[i/k])+1 。这个dp是O(n2) 的,可以发现所有状态都是从更小的状态转移而来,因而可以用单调队列进行优化。单调队列优化dp是求形如dp[i]=min/maxj<i(dp[j])+g[i] 时将求极值的部分优化掉的方法。它的特点是取max/min 的是小于i 的一个区间,队列保存了之前扫描过的信息,不需要再重复扫描了,队列中维护的是最优值、次优值…依此类推。而且新加入队列的元素若比队列中的某些元素更优,那么这些元素就再也不可能被取到,可以直接从队尾出队,也就是说新入队的元素一定处于队尾的位置。

#include <bits/stdc++.h>

using namespace std;


const int maxn = 1000010;
int dp[maxn];
int q[maxn];
int id[maxn];
int f,r;
int main(){
    int T,x,k,t;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&x,&k,&t);
        f = r = 0;
        dp[1] = 0;
        id[r] = 1;
        q[r++] = dp[1];
        for(int i = 2;i <= x;i++){
            while(f<r&&id[f]+t<i) f++;
            int v = q[f];
            if(f == r) v = maxn;
            dp[i] = v+1;
            dp[i] = min(dp[i],(i%k==0?dp[i/k]:maxn)+1);
            while(f<r && q[r-1]>= dp[i]) r--;
            id[r] = i;
            q[r++] = dp[i];

        }
        printf("%d\n",dp[x]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章