Description
小胡同学是个热爱运动的好孩子。
每天晚上,小胡都会去操场上跑步,学校的操场可以看成一个由n 个格子排成的一个环形,格子按照顺时针顺序从0 到n 1 标号。
小胡观察到有m 个同学在跑步,最开始每个同学都在起点(即0 号格子),每个同学都有个步长ai,每跑一步,每个同学都会往顺时针方向前进ai 个格子。由于跑道是环形的,如果
一个同学站在n 1 这个格子上,如果他前进一个格子,他就会来到0。
他们就这样在跑道上上不知疲倦地跑呀跑呀。小胡同学惊奇地发现,似乎有些格子永远不会被同学跑到,他想知道这些永远不会被任何一个同学跑到的格子的数目,你能帮帮他
吗?(我们假定所有同学都跑到过0 号格子)。
Solution
有等式:
xai−yn≡gcd(ai,n)( modn)
(不要问我为什么)
所以,很显然,i点可以走到的所有点一定是它与n的gcd,
我们统计有多少个点可以走到,
枚举每个n个因数d,看看有没有
ai
符合条件,如有符合的就说明有
φ(d)
个点可以走到(是phi的原因是防止统计重复)
Code
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=60;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a[N],b[N][2],b0;
int gcd(int x,int y){return y?gcd(y,x%y):x;}
bool OK(int q)
{
fo(i,1,m)if(0==q%a[i])return 1;
return 0;
}
int phi(int q)
{
int w=q,ans=q;
for(int i=2;i*i<=w;i++)if(w%i==0)
{
while(w%i==0)w/=i;
ans=ans/i*(i-1);
}
if(w>1)ans=ans/w*(w-1);
return ans;
}
void ss(int q,int e)
{
if(q>b0)
{
if(OK(e))ans+=phi(n/e);
return;
}
ss(q+1,e);
fo(i,1,b[q][0])ss(q+1,e*=b[q][1]);
}
int main()
{
freopen("running.in","r",stdin);
freopen("running.out","w",stdout);
int q,w;
read(n),read(m);
fo(i,1,m)a[i]=gcd(read(q),n);
for(w=2,q=n;w*w<=q;w++)if(q%w==0)
{
b[++b0][1]=w;
while(q%w==0)b[b0][0]++,q/=w;
}
if(q>1)b[++b0][1]=q,b[b0][0]=1;
ss(1,1);
printf("%d\n",n-ans);
return 0;
}