HDOJ 5945 Fxx and game

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5945


题意:给我们k,t,我们每次能把一个数减去一个小于等于t的数,如果当前数是k的倍数,可以除以k,问我们将X变为1最少需要的操作数。

首先,这题小编第一反应是贪心,当时贪心的想法就是能除尽量除,如果不能除就减到可以除,交上去直接A了也没多想,结果比赛结束不到一分钟就被hack了。那么我们先来分析一下贪心为什么不对,我们举个例子,比如说9 4 5这组数据,如果我们按这个贪心策略的话就是先减去1,使得变成4的倍数8,再除4,再减一,3步,但是实际上我们直接连续减两次就直接能够达到我们的要求。

那么我们就可以考虑dp来解决,用dp[i]表示i这个数变成1最少需要的次数的话,那么dp[i] = min(dp[i-1]+1, dp[i-2]+1……dp[i-t]+1, dp[i/k]+1),考虑到我们需要得到前t项里的最小值,我们可以使用单调队列。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 10;  
int T,n,m,x,k,t,d[maxn];  
struct node
{  
    int id, v;  
    node(int id=0, int v=0):id(id), v(v) {}  
}a[maxn];  
int main()
{  
    scanf("%d",&T);  
    while(T--)
	{  
        scanf("%d%d%d", &x, &k, &t);  
        memset(d, 0x3f, sizeof(d));  
        d[1] = 0;  
        int l = 0, r = 0;  
        a[0] = node(1, 0);  
        for(int i = 2; i <= x; i++)
		{
            if(i % k == 0) d[i] = min(d[i], d[i/k]+1);  
            while(a[l].id < i-t && l <= r) l++;  
            if(l > r)
			{
                l--;  
                a[l] = node(i, d[i]);  
                continue;  
            }  
            d[i] = min(d[i], a[l].v+1);  
            while(d[i] < a[r].v && r >= l) r--;  
            a[++r] = node(i, d[i]);  
        }  
        printf("%d\n", d[x]);  
    }  
    return 0;  
}  


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值