hdu 5945 单调队列优化的DP

来源:互联网 发布:淘宝卖家版怎么登陆 编辑:程序博客网 时间:2024/05/29 14:13


题意:给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中次数最小的那个数的下标。


单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。


以单调不减队列为例:队列内的元素(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);


#include<bits/stdc++.h>using namespace std;const int maxn = 2e6 + 10;#define INF 0x3f3f3f3ftypedef pair<int,int> P;typedef long long ll;int dp[maxn];int temp[maxn];int main(){    int Tcase;    scanf("%d",&Tcase);    while(Tcase --)    {        int x,k,t;        scanf("%d%d%d",&x,&k,&t);        int l = 1,r = 1;dp[1] = 0;temp[r] = 1;        for(int i = 2; i <= x; i ++)        {            dp[i] = INF;            while(l <= r && temp[l] < i - t)l ++;            if(l <= r)dp[i] = dp[temp[l]] + 1;            if(i % k == 0)dp[i] = min(dp[i],dp[i / k] + 1);            while(l <= r && dp[temp[r]] >= dp[i])r --;            temp[++ r] = i;        }        printf("%d\n",dp[x]);    }    return 0;}


原创粉丝点击