HDU 5945:Fxx and game

HDU 5945:Fxx and game

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5945

题目大意:共$T$组数据,每组给三个数$X$、$t$、$k$,问将$X$变成$1$最少需要几次操作.共两种操作:

  1.将$X-i(0 \leqslant i \leqslant t)$;2.将$X/k$($X$被$k$整除)

DP+单调队列

很明显是道DP题,定义状态:$dp[i]$为从$X$到$i$的最小操作数,

故状态转移方程为:$dp[i]=min\{min\{dp[i+p]|0 \leqslant p \leqslant t\},dp[i \times k])\}$.

朴素的DP算法复杂度为$O(n^2)$.

若用优先队列维护$min\{dp[i+p]|0 \leqslant p \leqslant t\}$,即可将总复杂度降为$O(nlgn)$,实际耗时1419MS,勉强能过:\

/*注意$t=0$的情况下,仅能进行第二种操作*/

代码如下:

 1 #include <cstdio>
 2 #include <queue>
 3 #include <cstring>
 4 #define Min(a,b) (a<b?a:b)
 5 #define N 1000005
 6 using namespace std;
 7 const int inf=0x0fffffff;
 8 int T,x,k,t,dp[N];
 9 struct node{
10     int id,v;
11     node(int _id=-1,int _v=inf){
12         id=_id;v=_v;
13     }
14     bool operator < (const node b)const{
15         return v>b.v;
16     }
17 };
18 priority_queue<node>q;
19 void init(){
20     scanf("%d%d%d",&x,&k,&t);
21     if(k)for(int i=0;i<x;++i)dp[i]=inf;
22     while(!q.empty())q.pop();
23     q.push(node(x,0));
24     dp[x]=0;
25 }
26 int main(void){
27     scanf("%d",&T);
28     while(T--){
29         init();
30         if(t){
31             for(int i=x-1;i>0;--i){
32                 node tmp=q.top();
33                 while(tmp.id>t+i){
34                     q.pop();
35                     tmp=q.top();
36                 }
37                 if((long long)k*i<=x)tmp.v=Min(tmp.v,dp[k*i]);
38                 dp[i]=tmp.v+1;
39                 q.push(node(i,dp[i]));
40             }
41             printf("%d\n",dp[1]);
42         }else{
43             int ans=0;
44             while(x!=1){
45                 x/=k;
46                 ans++;
47             }
48             printf("%d\n",ans);
49         }
50     }
51 }
DP+优先队列

注意到若添加进优先队列中的$dp[i]$是队列中的较小的值,那么队列中原有的比$dp[i]$大的元素将不再有价值.

故可以用一个递增的单调队列维护$min\{dp[i+p]|0 \leqslant p \leqslant t\}$,即可将总复杂度将为$O(n)$.

代码如下:

 1 #include <cstdio>
 2 #include <deque>
 3 #include <cstring>
 4 #define Min(a,b) (a<b?a:b)
 5 #define N 1000005
 6 using namespace std;
 7 const int inf=0x0fffffff;
 8 int T,x,k,t,dp[N];
 9 struct node{
10     int id,v;
11     node(int _id=-1,int _v=inf){
12         id=_id;v=_v;
13     }
14 };
15 deque<node>q;
16 void init(){
17     scanf("%d%d%d",&x,&k,&t);
18     if(k)for(int i=0;i<x;++i)dp[i]=inf;
19     q.clear();
20     q.push_back(node(x,0));
21     dp[x]=0;
22 }
23 int main(void){
24     scanf("%d",&T);
25     while(T--){
26         init();
27         if(t){
28             for(int i=x-1;i>0;--i){
29                 node tmp=q.front();
30                 while(tmp.id>t+i){
31                     q.pop_front();
32                     tmp=q.front();
33                 }
34                 if((long long)k*i<=x)tmp.v=Min(tmp.v,dp[k*i]);
35                 dp[i]=tmp.v+1;
36                 tmp=q.back();
37                 while(dp[i]<tmp.v){
38                     q.pop_back();
39                     if(q.empty())break;
40                     tmp=q.back();
41                 }
42                 q.push_back(node(i,dp[i]));
43             }
44             printf("%d\n",dp[1]);
45         }else{
46             int ans=0;
47             while(x!=1){
48                 x/=k;
49                 ans++;
50             }
51             printf("%d\n",ans);
52         }
53     }
54 }

 

转载于:https://www.cnblogs.com/barrier/p/6431526.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值