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