歌名 - 歌手
0:00

    【NOIP2016提高A组五校联考2】running

    题目

    小胡同学是个热爱运动的好孩子。
    每天晚上,小胡都会去操场上跑步,学校的操场可以看成一个由n个格子排成的一个环形,格子按照顺时针顺序从0 到n- 1 标号。
    小胡观察到有m 个同学在跑步,最开始每个同学都在起点(即0 号格子),每个同学都有个步长ai,每跑一步,每个同学都会往顺时针方向前进ai 个格子。由于跑道是环形的,如果一个同学站在n-1 这个格子上,如果他前进一个格子,他就会来到0。
    他们就这样在跑道上上不知疲倦地跑呀跑呀。小胡同学惊奇地发现,似乎有些格子永远不会被同学跑到,他想知道这些永远不会被任何一个同学跑到的格子的数目,你能帮帮他
    吗?(我们假定所有同学都跑到过0 号格子)。

    分析

    首先对于一个人 i, 显然,那么它所能到达的格子一定是$gcd(ai,n) \(的倍数。 所以我们枚举n的约数d,如果有一个i,\)gcd(a_i,n)|d\(,说明所有\)gcd(j,n) = d$ 的格子都能被到达,答案加上 \(φ(\dfrac{n}{d})\) 即可。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=55;
    using namespace std;
    int a[N],n,m,ans;
    int gcd(int x,int y)
    {
        if(y==0) return x;    
        if(x<y) return gcd(y,x);    
        else return gcd(y, x%y); 
    }
    int phi(int x)
    {
    	int sum=x,e=x;
    	for(int i=2;i<=int(sqrt(e));i++)
    	{
    		if(x%i==0)
    		{
    			sum=sum/i*(i-1);
    			while(x%i==0) x/=i;
    		}
    	}
    	if(x>1)
    	{
    		sum=sum/x*(x-1);
    	}
    	return sum;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=int(sqrt(n));i++)
    	{
    		if(n%i==0)
    		{
    		for(int j=1;j<=m;j++)
    			if(i%gcd(a[j],n)==0)
    			{
    				ans+=phi(n/i);
    				break;
    			}
    		for(int j=1;j<=m;j++)
    			if((n/i)%gcd(a[j],n)==0)
    			{
    				ans+=phi(i);
    				break;
    			}
    		}
    	}
    	cout<<n-ans<<endl;
    }
    
    
    posted @ 2018-05-20 22:47  无尽的蓝黄  阅读(177)  评论(0编辑  收藏  举报