Fxx and game
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 486 Accepted Submission(s): 120
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.
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。
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
给定x, k, t,求将x变成1的最小步数,每次可以减去(1到t的值),或者如果当前值余k等于0可以除以k。
解:因为t的范围很大,所以用搜索容易超时,这里借助单调队列。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1000005;
const int inf = 0x3f;
int q[N], f[N];
int main()
{
int T, x, k, t;
scanf("%d", &T);
while(T--)
{
scanf("%d %d %d", &x, &k, &t);
memset(f,inf,sizeof(f));
q[0]=1, f[1]=0;
int l=0, r=1;
for(int i=2;i<=x;i++)
{
if(!(i%k))
f[i]=min(f[i],f[i/k]+1);
while(l<r&&q[l]+t<i) l++;
f[i]=min(f[i],f[q[l]]+1);
while(l<r&&f[i]<f[q[r-1]]) r--;
q[r++]=i;
}
printf("%d\n",f[x]);
}
return 0;
}
单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。
以单调不减队列为例:队列内的元素(e1,e2,e3...en)存在(e1<=e2<=e3<=...<=en)的关系,所以队首元素e1一定是最小的元素。与优先队列不同的是,当有一个新的元素e入队时,先要将队尾的所有大于e的元素弹出,以保证单调性,再让元素e入队尾。
例如这样一组数(1,3,2,1,5,6),进入单调不减队列的过程如下:
1入队,得到队列(1);
3入队,得到队列(1,3);
2入队,这时,队尾的的元素3>2,将3从队尾弹出,新的队尾元素1<2,不用弹出,将2入队,得到队列(1,2);
1入队,2>1,将2从队尾弹出,得到队列(1,1);
5入队,得到队列(1,1,5);
6入队,得到队列(1,1,5,6);
代码实现:
访问队首和删除队首元素的时间复杂度为O(1),在队尾加入元素的最坏情况下的时间复杂度为O(n),n为队列当前长度。所以,可以采用二分查找,来确定新加入元素应该插入的位置。