题意:给x,k,t,求x最快衰减到1的速度。其中x可以减去1-t之间的一个数,k|x时可以除以k。
做法:直接搜或者dp都会跪。问题在于已经更新的段被重复访问次数太多。为了避免这个问题,我们从1开始bfs,并且记录每个点所在被更新线段的左端点为他的father,这样bfs更新线段的时候,只需要从father处向左更新,并且做一下类似并查集的维护操作即可,这样每个点只会被遍历一次。
代码:
#include <bits/stdc++.h>
using namespace std;
int u[1050000];
int ans[1050000];
int x, k, t;
bool vis[1050000];
struct node{
int t;
int id;
};
int find(int x){
if(x==u[x])return x;
return u[x]=find(u[x]);
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
queue<node>que;
memset(ans, 0x3f3f3f3f, sizeof(ans));
memset(vis, false, sizeof(vis));
scanf("%d%d%d", &x, &k, &t);
node st;
for(int i=1;i<=1000000;i++)u[i]=i;
st.t=0;
st.id=1;
que.push(st);
vis[1]=true;
ans[1]=0;
//int tag=-1;
while(!que.empty())
{
node tmp=que.front();
que.pop();
//printf("%d %d\n", tmp.id, tmp.t);
if((long long)tmp.id*k<=x&&!vis[tmp.id*k]){
node ttmp;
ttmp.id=tmp.id*k;
ttmp.t=tmp.t+1;
ans[ttmp.id]=ttmp.t;
vis[ttmp.id]=true;
que.push(ttmp);
}
if(tmp.id<x){
int r=min(tmp.id+t, x);
//printf("%d\n", r);
r=find(r);
//printf("%d\n", r);
int root=find(tmp.id+1);
for(int i=r;i>tmp.id;i--){
u[i]=root;
if(vis[i])continue;
vis[i]=true;
ans[i]=tmp.t+1;
node ttmp;
ttmp.id=i;
ttmp.t=tmp.t+1;
que.push(ttmp);
}
}
}
printf("%d\n", ans[x]);
}
}