1.暴走的猴子(walk.pas/c/cpp)
【题目描述】
从前有一个森林,森林里生活着一群猴子,这里猴子有个恶趣味——暴走。现在给你这个森林里的树木描述,你能计算出这只猴子在暴走k步后会蹦达到哪里吗(友情提示:由于你上周帮助猎人写程序打死了猴子父亲,所以今天猴子特别不爽,故意暴走了很多很多步来为难你,从而导致了k非常的大,做好心里准备噢~)
【输入数据】
第一行两个数n,m表示树木数和询问次数
接下来n行,第i行一个数ai表示这只猴子当前在第i棵树的话,下一步会走到第ai棵树
接下来m行,每行两个数t,k,询问如果当前猴子在第t棵树,k步之后它会到第几棵树
【输出数据】
m行为每次询问的结果
【样例输入】
3 2
2
3
2
1 2
2 4
【样例输出】
3
2
【数据范围】
共十个测试点,每个测试点数据规模如下所示
1.n=10^2,m=n,k<=10^2
2.n=10^3,m=n,k<=10^3
3.n=10^4,m=1,k<=10^9
4.n=10^5,m=1,k<=10^9
5.n=10^5,m=1,k<=10^12
6.n=10^5,m=1,k<=10^15
7.n=10^5,m=1,k<=10^18
8.n=10^5,m=n,k<=10^12
9.n=10^5,m=n,k<=10^15
10.n=10^5,m=n,k<=10^18
【时限】
1s
①由于每棵树都有跳到的下一棵树的编号,所有从当前这棵树开始跳,一定会从某时刻进入循环节,用寻找循环节的方法可以拿到70分。
②说这个方法之前,先说一下:任意一个数总可以拆成2的几次方相加,如31=20+22+24
一个非常好的方法是倍增f[k,i]代表从i开始跳2^k步会到哪里,初始
f[0,i]=next[i]
f[k,i]=f[k-1,f[k-1,i]]
复杂度m*log(n);
C++ Code
#include<cstdio>
#define MAXN 100000+10
int n,m,next[MAXN],f[MAXN][100];
bool ji(int x)
{
if(x%2==0)return false;else return true;
}
int main()
{
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&next[i]);
}
for(i=1;i<=n;i++)f[i][0]=next[i];
int j;
for(j=1;j<=60;j++)
for(i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
int t,sum=0;
long long k;
for(i=1;i<=m;i++)
{
sum=0;
scanf("%d%I64d",&t,&k);
while(k!=0)
{
if(ji(k)) t=f[t][sum];
k=k/2;
sum++;
}
printf("%d\n",t);
}
return 0;
}