hdu 5945 Fxx and game(dp+单调队列! bc#89)

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=Xi(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(1T20) indicating the number of test cases.

As for the following T lines, each line contains three integers X,k,t(0t106,1X,k106)

For each text case,we assure that it's possible to make X become 1。
 


Output
For each test case, output the answer.
 
题意:给你3个数x,k,t。你可以进行如下操作,x减去0~t,如果x能被k整除x可以变为x/k。问你最少进行
几步操作能让x变为1.
 
看到这道题目我们大概会想到用贪心来做,但是单纯贪心有些数据是过不了的,只能说出数据的人太厉害了。于是
我们只能用正常的方法解决这道题目了。
我们倒着来解这道题目,从1~x也是一样的。我们设dp[i]表示从1~i最少要几步。于是我们很容易会得到这样
的转移方程if i%k == 0 dp[i]=min(dp[i],dp[i/k]+1),每次处理一下dp[i]=min(dp[i],dp[(i-t)~(i-1)])。
如何快速求(i-t)~(i-1)的最小值呢?
可以用线段树求,但是数据是10的6次,有数据能让线段树超时。所以线段树out,于是我们要用单调队列求最
小值
#include <iostream>
#include <deque>
#include <cstring>
using namespace std;
const int M = 1e6 + 10;
int dp[M];
int main()
{
	int n;
	cin >> n;
	while(n--) {
		int x , k , t;
		cin >> x >> k >> t;
		deque<int>q;
        memset(dp , 0X3f , sizeof(dp));
		dp[1] = 0;
		q.push_front(1);
		for(int i = 2 ; i <= x ; i++) {
			if(i % k == 0) {
				dp[i] = min(dp[i / k] + 1 , dp[i]);
			}
                        while(!q.empty() && i - q.back() > t) {
				q.pop_back();
			}
                        if(!q.empty())
			        dp[i] = min(dp[i] , dp[q.back()] + 1);
			while(!q.empty() && dp[q.front()] > dp[i]) {
				q.pop_front();
			}
			q.push_front(i);
		}
		cout << dp[x] << endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/6013198.html