[hdu 5945 Fxx and game] dp+单调队列

来源:互联网 发布:常用的机械制图软件 编辑:程序博客网 时间:2024/05/24 01:49

[hdu 5945 Fxx and game] dp+单调队列

题目链接:[hdu 5945 Fxx and game]
题意描述:请看BestCoder中文题面…传松门
青年理论计算机科学家Fxx给的学生设计了一款数字游戏。
一开始你将会得到一个数X,每次游戏将给定两个参数k,t, 任意时刻你可以对你的数执行下面两个步骤之一:

  1. X=Xi(1<=i<=t);
  2. XkX=X/k

现在Fxx想要你告诉他最少的运行步骤,使X变成1
解题思路:用dp[z]表示数z变换到1的最少变换次数。显然有:

dp[z]={min{dp[zi]}+1,min{dp[zi],dp[z/k]}+1,(z%k0)(z%k=0)(,1it).

min{dp[zi]}(1it) 就相当于求区间[zt,z]的区间最小值。纯暴力,复杂度会有O(N2);在这个题目里面, 线段树还是会超时,复杂度为O(Xlog2(X))。如果考虑用单调队列来优化,复杂度为O(N)
单调队列的队首永远是dp最小值。

#include <bits/stdc++.h>using namespace std;int T, X, k, t;const int MAXN = 1e6 + 5;const int INF = 0x3f3f3f3f;queue<int> Q;int dp[MAXN];int main() {//    freopen("E:\\ACM\\input.txt", "r", stdin);    scanf("%d", &T);    while(T --) {        scanf("%d %d %d", &X, &k, &t);        memset(dp, 0x3f, sizeof(dp));        while(!Q.empty()) Q.pop();        dp[1] = 0;        Q.push(1);        for(int z = 1; z <= X; z++) {            while(!Q.empty() && Q.front() < z - t) Q.pop();            if(!Q.empty()) dp[z] = min(dp[z], dp[Q.front()] + 1);            if(z % k == 0) dp[z] = min(dp[z], dp[z / k] + 1);            while(!Q.empty() && dp[Q.front()] >= dp[z]) Q.pop();            Q.push(z);        }        printf("%d\n", dp[X]);    }    return 0;}
1 0
原创粉丝点击