【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;
}

原文地址:https://www.cnblogs.com/chen1352/p/9065037.html