zoukankan      html  css  js  c++  java
  • 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]dp[i]表示i变为1需要的方法数
    因为dp[i]可由dp[i/k]dp[i/k], dp[ij](0<=j<=t)dp[i−j](0<=j<=t)转移过来
    我们可以写出状态转移方程:

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


    边界条件:dp[1]=0
    时间复杂度: O(xt)O(xt)

    但是该方法时间复杂度过高,必须要优化
    单调队列的条件是:首先队列的值保持单调,维护答案一直在队首,然后队列里面的时间表现单调性,还有就是弹掉的东西一定没有新入队的优
    维护一个dp[i]从队尾到队头递增的队列

    因此我们每次算好dp[i]的时候把队尾中dp值小于等于dp[i]的都出队(队列里面的都是下标比i大的,值又没i优,是无用的)
    dp[i]=min(dp[q[head]],dp[i/k])+1dp[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;
        }
    }
    版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢
  • 相关阅读:
    word文档的图片怎么保存到Web编辑器上
    如何在linux下查看gpu信息

    lua注释
    readDouble
    ..在lua中运用
    C++条件分支结构
    C++条件分支结构
    Flink基础(十六):Table API 和 Flink SQL(一)整体介绍
    Flink基础(十四):DS简介(14) 搭建Flink运行流式应用
  • 原文地址:https://www.cnblogs.com/birchtree/p/9845851.html
Copyright © 2011-2022 走看看