NOIP2013提高组复赛 转圈游戏 解题报告



描述

n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位置编号,从0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此类推。

游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,……,依此类推,第n − m号位置上的小伙伴走到第 0 号位置,第n-m+1 号位置上的小伙伴走到第 1 号位置,……,第 n-1 号位置上的小伙伴顺时针走到第m-1 号位置。

现在,一共进行了 10^k 轮,请问 x 号小伙伴最后走到了第几号位置。

格式

输入格式

输入共 1 行,包含 4 个整数 n、m、k、x,每两个整数之间用一个空格隔开。

输出格式

输出共 1 行,包含 1 个整数,表示 10^k 轮后 x 号小伙伴所在的位置编号。

样例1

样例输入1[复制]

10 3 4 5

样例输出1[复制]

5

限制

每个测试点1s。

提示

对于 30%的数据,0 < k < 7; 
对于 80%的数据,0 < k < 10^7; 
对于 100%的数据,1 < n < 1,000,000,0 < m < n,1 <= x <=n,0 < k < 10^9。

来源

NOIP 2013 提高组 Day 1


 

简单分析:

 

NOIP2013提高组复赛 转圈游戏 解题报告_第1张图片

显然有环(即转圈的情况),即相当于从出发点直接走a个点,a:=(m*10^k) mod n10^k这样输入是错误的】;

而题目数据太大,使用普通方法时间无法通过(我试了一下,能过百分之30左右)

所以想到优化10^k时的运算,即快速幂

NOIP2013提高组复赛 转圈游戏 解题报告_第2张图片

 


 

 

代码如下:program circle;

var

n,m,x,dx:longint;

k:longint;

function kuaisumi(a,b,p:longint):longint;{快速幂}

var

  

快速幂,核心操作就是转化二进制

 

t,r:longint;

begin

r:=1;

t:=a;

while b>0 do

begin

if (b and 1)=1 then r:=r*t mod p; {也就是取b的二进制最末位}

t:=t*t mod p;

b:=b shr 1; {也就是去掉b的二进制最末位}

end;

exit(r);

end;

begin

assign(input,'write.in');

reset(input);

assign(output,'write.out');

rewrite(output);

readln(n,m,k,x);

dx:=kuaisumi(10,k,n);

dx:=(dx*m mod n+x) mod n;(化简圈数)

writeln(dx);

close(input);

close(output);

end.

更短的代码(方法相同)

program circle;

var a,n,y,k,m,x:longint;

begin

 readln(n,m,k,x);

 a:=m; y:=10;

 while k<>0 do

  begin

  if k and 1=1

  then a:=(a*y) mod n;

  y:=y*y mod n;

  k:=k shr 1;

  end;

 write((a+x)mod n);

end.

 

简单分析:

 


显然有环(即转圈的情况),即相当于从出发点直接走a个点,a:=(m*10^k) mod n10^k这样输入是错误的】;

而题目数据太大,使用普通方法时间无法通过(我试了一下,能过百分之30左右)

所以想到优化10^k时的运算,即快速幂

 

 

代码如下:program circle;

var

n,m,x,dx:longint;

k:longint;

function kuaisumi(a,b,p:longint):longint;{快速幂}

var

快速幂,核心操作就是转化二进制

 

t,r:longint;

begin

r:=1;

t:=a;

while b>0 do

begin

if (b and 1)=1 then r:=r*t mod p; {也就是取b的二进制最末位}

t:=t*t mod p;

b:=b shr 1; {也就是去掉b的二进制最末位}

end;

exit(r);

end;

begin

assign(input,'write.in');

reset(input);

assign(output,'write.out');

rewrite(output);

readln(n,m,k,x);

dx:=kuaisumi(10,k,n);

dx:=(dx*m mod n+x) mod n;(化简圈数)

writeln(dx);

close(input);

close(output);

end.

更短的代码(方法相同)

program circle;

var a,n,y,k,m,x:longint;

begin

 readln(n,m,k,x);

 a:=m; y:=10;

 while k<>0 do

  begin

  if k and 1=1

  then a:=(a*y) mod n;

  y:=y*y mod n;

  k:=k shr 1;

  end;

 write((a+x)mod n);

end.

你可能感兴趣的:(NOIP解题报告)