• 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 imes 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
    ",dp[1]);
    42         }else{
    43             int ans=0;
    44             while(x!=1){
    45                 x/=k;
    46                 ans++;
    47             }
    48             printf("%d
    ",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
    ",dp[1]);
    45         }else{
    46             int ans=0;
    47             while(x!=1){
    48                 x/=k;
    49                 ans++;
    50             }
    51             printf("%d
    ",ans);
    52         }
    53     }
    54 }
  • 相关阅读:
    linux系统用户登陆时脚本执行顺序
    stm32 win7 64位虚拟串口驱动安装失败解决办法
    python全栈day6
    python全栈day5
    江湖救急(处理域名未备案网站问题)
    python全栈day4
    python全栈day3
    python全栈day2
    python全栈day1
    PHP 跨域之header
  • 原文地址:https://www.cnblogs.com/barrier/p/6431526.html
Copyright © 2020-2023  润新知