running
题目大意
学校的操场可以看成一个由
n
个格子排成的一个环形,格子按照顺时针顺序从
小胡观察到有
m
个同学在跑步,最开始每个同学都在起点(即
求永远不会被跑到的格子的数目。
数据范围
对于
题解
首先我们先证明一个定理:第i个同学经过的格子一定是
这个易证:设
ai
*
k1
mod
n
=x
ai
*
k1
-
k2
*
n
=x
ai∗k1c
*
c
-k2∗nc *
c
=x
ai∗k1−k2∗ngcd(ai,n)
*
gcd
(
ai
,
n
)=x
其中 ai∗k1−k2∗ngcd(ai,n) 很显然 是整数,得证!
接下来我们需要证明第
i
个同学一定会经过所有是
首先,第
ai∗ngcd(ai,n)∗ai = ngcd(ai,n) ,
刚好不重复地把所有是 gcd ( ai , n )的倍数的格子都走了一遍(结合一开始证明的结论可得出)。
有了这个结论,这题就容易多了,通过这个结论,我们就可以算出一定会被经过的格子数目,如果算成
那我们怎么办了?
用格子的位置
i
与
枚举一个
n
的约数
这样算的话每个合法格子既不会被算重也不会被算漏。
Code(Pascal)
var
a,g:array[0..50] of int64;
n,m,ljz,ans,o:int64;
i,l:longint;
ys:array[0..100,1..2] of int64;
function gcd(a,b:int64):int64;
var
t:int64;
begin
repeat
t:=b;
b:=a mod b;
a:=t;
until b=0;
exit(a);
end;
procedure js(p:int64);
var
i,k:longint;
begin
p:=n div p;
k:=p;
for i:=2 to trunc(sqrt(p)) do
if k mod i=0 then
begin
p:=(p div i)*(i-1);
while k mod i=0 do
k:=k div i;
end;
if k>1 then p:=(p div k)*(k-1);
ans:=ans+p;
end;
begin
readln(n,m);
for i:=1 to m do
begin
read(a[i]);
g[i]:=gcd(a[i],n);
end;
for i:=1 to trunc(sqrt(n)) do
if n mod i=0 then
begin
for l:=1 to m do
if i mod g[l]=0 then
begin
js(i);
break;
end;
if i<>sqrt(n) then
for l:=1 to m do
if n div i mod g[l]=0 then
begin
js(n div i);
break;
end;
end;
writeln(n-ans);
end.