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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章