【HDU 5945】Fxx and game(DP+单调队列)

【HDU 5945】Fxx and game(DP+单调队列)

啊啊啊啊啊啊啊。。。BC第二题就这么难了……好菜啊……这游戏没法玩了啊……。。。

膜一下队伍主力 金QAQ巨。。。现两号BC金。。Orz……@a1s4z5

顺吐槽一发……大家BC页面会卡么……宿舍进BC卡得要死……具体卡成什么样子……校园网进不去热点也卡的要命,耐心等待题面一帧帧 浮现 出来……然后已经被甩出去好几条街了……然后……咦……这A题坑点很迷啊,Hack肯定很爽啊,耐心等待页面 一条条 出现后……双击room里一人的A题……我选择放弃。。。。

从此BC成路人……

言归正传,这题还是很好的……即使因此分掉了一大截……摔。。

具体的:给出x,t,k,要将数字x变成1。操作有二:
1.把数字x变成数字y(0 <= x-y <= t),消耗一步。
2.x->x/k(if x%k == 0),消耗一步。

一开始的想法很犀利……定义 d p [ i ] dp[i] dp[i]为从x变成i的最少步数,那么答案其实是 m i n ( d p [ i ] ) ( 1 < = i < k ) min(dp[i])(1 <= i < k) min(dp[i])1<=i<k,因为到k的话肯定会/k变成1,其实就是dp[1],所以只考虑1~k-1。

然后对于i(1 <= i < k),找到最大的y,满足y%k == 0 && y/k == i && y <= x
然后计算从x变成y,然后从y变成i,从i变成1。前后除t即可,中间就有点暴力了。。然后就爆炸了……然后刚才发现有地方写搓了。。然后改了后测了一些数据发现这种贪心是有问题的……然后还是爆炸了……

还是规规矩矩的做法吧,dp[i]表示i变成1的最少步数。
那么如果i%k != 0 那么dp[i] = min(dp[j])+1(0 <= i-j <= t)
如果i%k == 0,最小值里再取个dp[i/k]。

暴力的话会超时,维护一个跟i距离t内的单调队列,队列里的数值从左到右单调递增,右边入队左边取值即为t内最少步数。

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 1123456;

int s[maxn];
int dp[maxn];

int main()
{
	//fread("");
	//fwrite("");

	int t,T,l,r,x,k;

	scanf("%d",&T);

	while(T--)
	{
		scanf("%d%d%d",&x,&k,&t);

		dp[1] = 0;
		l = 0;
		r = -1;

		s[++r] = 1;

		for(int i = 2; i <= x; ++i)
		{
			if(i%k == 0 && k != 1) dp[i] = dp[i/k]+1;

			if(l <= r) 
			{
				if(i%k == 0 && k != 1) dp[i] = min(dp[i],dp[s[l]]+1);
				else dp[i] =dp[s[l]]+1;
			}

			while(l <= r && dp[i] <= dp[s[r]])
				r--;

			s[++r] = i;

			while(l <= r && i-s[l] >= t) ++l;
		}

		printf("%d\n",dp[x]);
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值