有位好心人指点这道题的核心思想是sliding window(poj 2823),虽然这道题不咋地,但是窗口滑动确实是一个很好的思想
如何利用单调队列优化dp,是一个值得思考的问题
这道题用tail - head表示队列规模,而用head表示队首,tail-1表示队尾元素,队首和队尾元素是必然会有重合的(q.size() == 1),还是蛮有意思的
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1000005;
int dp[maxn];
int q[maxn];
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
int x, k, t;
scanf("%d%d%d", &x, &k, &t);
if(k == 1)
printf("%d\n", x / t + (x % t > 1));
else if(t == 0)
{
int xx = x;
int ans = 0;
while(xx > 1)
{
ans ++;
xx /= k;
}
printf("%d\n", ans);
}
else
{
int head = 1, tail = 2;//此时单调队列中已经有一个元素了,保证tail-head == 1
//此处比head = 0, tail = 1更为方便,因为坐标都是从1开始的
//但是队首下标不能跟随tail标记为2,因此用tail-1代表队尾元素,而用tail-head维持队列长度,两者互不关联
dp[1] = 0;
q[1] = 1;
for(int i = 2; i <= x; i ++)
{
while(head < tail && i - t > q[head]) head ++;
if(head < tail) dp[i] = dp[q[head]] + 1;
if(i % k == 0) dp[i] = min(dp[i], dp[i/k] + 1);
while(head < tail && dp[q[tail-1]] >= dp[i]) tail --;
tail ++;
q[tail-1] = i;
}
printf("%d\n", dp[x]);
}
}
return 0;
}