HDU 5945 題解(DP)(單調隊列)

題面:

Fxx and game
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 2264 Accepted Submission(s): 600

Problem Description
Young theoretical computer scientist Fxx designed a game for his students.

In each game, you will get three integers X,k,t.In each step, you can only do one of the following moves:

1.X=X−i(0<=i<=t).

2.if k|X,X=X/k.

Now Fxx wants you to tell him the minimum steps to make X become 1.

Input
In the first line, there is an integer T(1≤T≤20) indicating the number of test cases.

As for the following T lines, each line contains three integers X,k,t(0≤t≤106,1≤X,k≤106)

For each text case,we assure that it’s possible to make X become 1。

Output
For each test case, output the answer.

Sample Input
2
9 2 1
11 3 3

Sample Output
4
3

分析:

此題可用dp求解
分解子問題:我們設dp[i] 表示i變爲1需要的方法數
因爲dp[i]可由dp[i/k] , dp[ij](0<=j<=t) 轉移過來
我們可以寫出狀態轉移方程:

dp[i]=min(dp[i/k],dp[ij])+1(0<=j<=t)

邊界條件:dp[1]=0
時間複雜度: O(xt)

但是該方法時間複雜度過高,必須要優化
單調隊列的條件是:首先隊列的值保持單調,維護答案一直在隊首,然後隊列裏面的時間表現單調性,還有就是彈掉的東西一定沒有新入隊的優
維護一個dp[i]從隊尾到隊頭遞增的隊列

因此我們每次算好dp[i]的時候把隊尾中dp值小於等於dp[i]的都出隊(隊列裏面的都是下標比i大的,值又沒i優,是無用的)
dp[i]=min(dp[q[head]],dp[i/k])+1
最後在隊頭彈出不滿足條件的值

代碼:

#include<iostream>
#include<cstring>
#define maxn 1000020
using namespace std;
int c,x,k,t;
int dp[maxn],q[maxn];
int head,tail;
int main() {
    cin>>c;
    while(c--) {
        cin>>x>>k>>t;
        int ans=0;
        if(t==0) { //特判
            while(x!=1) {
                x/=k;
                ans++;
            }
        }else if(k==0) {
            if((x-1)%t==0) ans=(x-1)/t;
            else ans=(x-1)/t+1;
        } else {
            head=0,tail=1; 
            memset(q,0,sizeof(q));
            memset(dp,0x7f,sizeof(dp));
            dp[1]=0;
            q[head]=1;
            for(int i=2; i<=x; i++) {
                while(i-q[head]>t&&head<tail) head++;//單調隊列優化 
                dp[i]=dp[q[head]]+1;
                if(i%k==0) dp[i]=min(dp[i],dp[i/k]+1);
                while(dp[q[tail]]>dp[i]&&head<tail) tail--;
                q[++tail]=i;
            }
            ans=dp[x];
        }
        cout<<ans<<endl;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章