题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5945
题意:给3个数x, k, t。经一系列操作后,使x变为1,求最少的操作次数。具体操作为:每次x可以减去一个数0~t,或者除以k。
解析:本题使用dp,但是需要用单调队列进行优化。
动规需要从1开始,一直往上计算,直到x为止。
递归公式为:dp[i]=min(min(dp[i-t]~dp[i-1])+1,dp[i/k]+1)
单调队列:单调队列中的数字都是递增或者递减的。本题中队列用来保存下标,队首的下标总是对应i-1~i-t中次数最小的那个数的下标。
代码:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define N 1000005
using namespace std;
typedef long long ll;
int dp[N];
int pos[N];
int main()
{
int t, cnt;
scanf("%d", &t);
while(t--){
ll x, k, t;
scanf("%lld%lld%lld", &x, &k, &t);
cnt = 0;
if(t == 0){
while(x != 1){
x/=k;
cnt++;
}
printf("%d\n",cnt);
continue;
}
dp[1] = 0;
int l = 1, r = 1;
pos[1] = 1;
//dp[i]=min(min(dp[i-t]~dp[i-1])+1,dp[i/k]+1)
for(int i = 2; i <= x; i++){
while(l <= r && i - t > pos[l])l++;
dp[i] = dp[pos[l]] + 1;
if(i % k == 0)
dp[i] = min(dp[i], dp[i/k]+1);
while(l <= r && dp[pos[r]] >= dp[i]) r--;
pos[++r] = i;
}
printf("%d\n", dp[x]);
}
return 0;
}