您的位置:首页 > 其它

【动规递推】【120814测试】【NOIP第二次模拟赛】暴走的猴子

2012-08-20 19:46 288 查看
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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: