Fxx and game
Accepts: 74
Submissions: 1857
Time Limit: 3000/1500 MS (Java/Others)
Memory Limit: 131072/65536 K (Java/Others)
问题描述
青年理论计算机科学家Fxx给的学生设计了一款数字游戏。
一开始你将会得到一个数X,每次游戏将给定两个参数k,t, 任意时刻你可以对你的数执行下面两个步骤之一:
1.X=X−i(1<=i<=t)
2.2.若X为k的倍数,X=X/k。
现在Fxx想要你告诉他最少的运行步骤,使X变成11。
输入描述
第一行一个整数T(1≤T≤20)表示数据组数。
接下来T行,每行三个数X,k,t(<=1e6)
)
数据保证有解。
输出描述
输出共T行。
每行一个整数表示答案。
输入样例
2
9 2 1
11 3 3
输出样例
4
3
题解:写了一个bfs的,对我之前写的dp还耿耿于怀,就去找了一下,果然可行。
dp[i]表示1到i的最小花费。则状态转移为:
1:当i%k!=0时,dp[i]=min(dp[i],dp[j]+1)(i-t<=j<=i-1)
2:当i%k==0时,dp[i]=min(dp[i],dp[i/k]+1);
需要用一个单调队列为维护dp[j]。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <string.h>
#include <vector>
#define bababaa printf("!!!!!!!\n")
using namespace std;
const int N=1e6+10;
int dp[N];
int main()
{
int T,x,k,t;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&x,&k,&t);
deque<int>q;
q.push_back(1);
fill(dp+1,dp+x+1,1e9);
dp[1]=0;
for(int i=2; i<=x; i++)
{
dp[i]=min(dp[i],dp[q.front()]+1);
if(i%k==0)
dp[i]=min(dp[i],dp[i/k]+1);
while(!q.empty()&&dp[i]<dp[q.back()]) q.pop_back();//维护不递减队列
while(!q.empty()&&i-q.front()>=t)q.pop_front();//维护t(大于等于是因为这次维护是为i+1准备的)
q.push_back(i);
}
cout<<dp[x]<<endl;
}
}