HDU5945 Fxx and game

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

1. X=Xi(1it)

2.若 X k的倍数, 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 <script type="math/tex" id="MathJax-Element-13">i</script>的一个区间,队列保存了之前扫描过的信息,不需要再重复扫描了,队列中维护的是最优值、次优值…依此类推。而且新加入队列的元素若比队列中的某些元素更优,那么这些元素就再也不可能被取到,可以直接从队尾出队,也就是说新入队的元素一定处于队尾的位置。

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值