比赛时一直以为是个数学题,一直没有想到用优先队列优化DP
看来需要好好学一学

STL中貌似没有直接对应的,所以用数组模拟队列就🆗,用空间换时间,比STL要快一些哦

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string> 
using namespace std;

int T,x,k,t,l,r;
int dp[1000100],q[1000100];

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&x,&k,&t);
		memset(dp,0x3f,sizeof(dp));
		memset(q,0,sizeof(q));
		if(k == 0)
		{
			int s = 0;
			s = (x - 1) / t;
			printf("%d\n",s);
			continue;
		}
		if(t == 0)
		{
			int s = 0;
			while(x != 1)
			{
				s++;
				x /= k;
			}
			printf("%d\n",s);
			continue;
		}
		dp[1] = 0;
		q[1] = 1;
		l = 1; r = 1;
		for(int i = 2;i <= x; ++i)
		{
			while(l <= r && q[l] < i - t) l++;
			dp[i] = dp[q[l]] + 1;
			if(i % k == 0)
				dp[i] = min(dp[i] , dp[i / k] + 1);
			while(l <= r && dp[q[r]] >= dp[i]) r--;
			q[++r] = i;
		}
		printf("%d\n",dp[x]);
	}
    return 0;
}

形如dp[i]=max/min(f[k])+g[i] (k<i 且g[i]与k无关)时,可用单调队列优化。
优化的对象是f[k];

本来 i和k是要用两个for循环来套完,但是在此处,g[i]与k,无关,而f[k]又要滚动取最值,那么就可以在一个for循环中把f[k]得到最值,同时计算当前的g[i],(强调,for循环的遍历顺序要确定,要保证可能与g[i]产生结果的所有f[k]都已计算完毕)将两者的结果存入dp[i]中,就达到了降维的目的。

单调队列优化的DP,当然一定要有某一部分满足单调性,典型问题就是类似于滑动窗口问题,维护一个区间最值,随着所需要更新的元素变化而变化,然后看一个单调性特别的题。