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[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 }