[BC#89B]Fxx and game

来源:互联网 发布:网络打印共享器价格 编辑:程序博客网 时间:2024/06/05 08:21

题目大意

给定n、k、t。
对于一个数x,可以一步变成x/k(必须整除)或x-i(1<=i<=t)
求把n变成1的最少步数

DP

设f[i]表示i变成1的最少步数
显然f[i*k]=min(f[[i*k],f[i]+1)
那么对于减怎么办?
维护单调递增的单调队列,每次从队头取决策,如果队头不合法则踢出。
注意k=1或t=0

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=1000000+10;int f[maxn],dl[maxn];int i,j,k,l,t,n,m,ca,head,tail;int main(){    scanf("%d",&ca);    while (ca--){        scanf("%d%d%d",&n,&k,&t);        fo(i,1,n) f[i]=n;        f[1]=0;        f[k]=1;        dl[head=tail=1]=1;        fo(i,2,n){            while (head<=tail&&dl[head]<i-t) head++;            if (head<=tail) f[i]=min(f[i],f[dl[head]]+1);            if ((ll)i*k<=n) f[i*k]=min(f[i*k],f[i]+1);            while (head<=tail&&f[i]<=f[dl[tail]]) tail--;            dl[++tail]=i;        }        printf("%d\n",f[n]);    }}
0 0
原创粉丝点击