NOIP2013提高组复赛 转圈游戏 解题报告
2015-08-11 16:44
387 查看
描述
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简单分析:
显然有环(即转圈的情况),即相当于从出发点直接走a个点,a:=(m*10^k) mod n【10^k这样输入是错误的】;
而题目数据太大,使用普通方法时间无法通过(我试了一下,能过百分之30左右)
所以想到优化10^k时的运算,即快速幂
代码如下:program circle;
var
n,m,x,dx:longint;
k:longint;
function kuaisumi(a,b,p:longint):longint;{快速幂}
var
|
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.
![](http://img0.ph.126.net/woccrB7snEIR6xR7rKA6gw==/6630085901816491551.png)
简单分析:
![](http://img1.ph.126.net/jadarlX1vCPV-NsQFPeYlg==/6631230493419977329.png)
显然有环(即转圈的情况),即相当于从出发点直接走a个点,a:=(m*10^k) mod n【10^k这样输入是错误的】;
而题目数据太大,使用普通方法时间无法通过(我试了一下,能过百分之30左右)
所以想到优化10^k时的运算,即快速幂
![](http://img1.ph.126.net/YlC2VxWvVBLeNR9vFtE-bA==/6630267321235071478.png)
代码如下:program circle;
var
n,m,x,dx:longint;
k:longint;
function kuaisumi(a,b,p:longint):longint;{快速幂}
var
|
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.
相关文章推荐
- 肯特·贝克:改变人生的代码整理魔法
- 你应该学习哪种编程语言?
- [转]我们需要一种其他人能使用的编程语言
- 2013年冬至是什么时候 冬至是哪天
- DB2编程序技巧(1)
- DB2编程序技巧 (四)
- 女人VS编程_国庆快乐
- DB2编程序技巧 (六)
- DB2编程序技巧 (三)
- DB2编程序技巧 (九)
- DB2编程序技巧 (七)
- DB2编程序小小技巧
- DB2编程序技巧 (五)
- 2013年立冬是什么时候 立冬是几号 立冬的含义介绍
- 2013年什么时候数九 三九天(数九天)从哪天开始
- DB2编程序技巧 (一)
- DB2编程序技巧 (八)
- DB2编程序技巧 (十)
- VBS基础编程教程 (第1篇)
- VBS基础编程教程 (第3篇)