zoukankan      html  css  js  c++  java
  • NOIP2016提高A组五校联考2】running

    题意:学校的操场可以看成一个由n个格子排成的一个环形,格子按照顺时针顺序从0到n-1标号.有m个同学在跑步,最开始每个同学都在起点(即0号格子),每个同学都有个步长ai,每跑一步,每个同学都会往顺时针方向前进ai个格子.由于跑道是环形的,如果一个同学站在n-1这个格子上,如果他前进一个格子,他就会来到0.似乎有些格子永远不会被同学跑到,求这些格子的数目?(假设每个同学都跑到过0号格子)

    分析:首先我们来证明一个结论:对于同学i,它的步长为ai,则编号能被gcd(ai,n)整除的格子(即编号是gcd(ai,n)的倍数的格子),他都能经过.

    证明:设同学i能够经过编号为k的格子,即必定存在一个x,满足((x*ai))%(n=k).

    上式又等价于必定存在一对x和y使得(x*ai-y*n=k)

    如果你学了扩展欧几里得算法,就应该会知道,上式要有整数解,充要条件是(gcd(ai,n)|k),即k能被(gcd(ai,n))整除,也就是说所有编号能被gcd(ai,n)整除的格子(即编号是gcd(ai,n)的倍数的格子),同学i都能经过,证毕.

    知道了这个结论后,我们还是不能愉快地做题.因为有些格子会被多个同学经过,即对于同一个k,可能存在多个i使得(gcd(ai,n)|k)成立,即使没有这样的情况,也可能存在多个i使得不同的(gcd(ai,n))具有公因数,这种情况也会使得某些格子被多个同学经过.总而言之,我们要考虑去重.

    我们考虑枚举n的所有约数,对于一个约数x,如果有一个gcd(ai,n)能被x整除(即x是gcd(ai,n)的倍数),即同学i能够经过x,则不会对答案产生贡献.

    否则,对于所有的gcd(ai,n),如果有一个约数x不是它们的倍数,即所有同学都不会经过x,则所有x的倍数,也不会被经过,ans+=phi(n/x)[其中phi是欧拉函数,(phi(j)表示1到j中与j互质的数的个数)].这里我觉得是本题中最难理解的地方,好好理解一下,其实我们实际上要求的就是有多少个格子的编号k满足(gcd(k,n)=x),这个式子等价于(gcd(frac{k}{x},frac{n}{x})=1)(不信的话自己手写几个例子看看),即(frac{k}{x})(frac{n}{x})互质,即我们现在要求的就是有多少个k满足(frac{k}{x})(frac{n}{x})互质,又因为x是k和n的最大公约数,所以(frac{k}{x})(frac{n}{x})都是整数,所以根据欧拉函数的定义,就等价于求phi(n/x)了.

    为了方便,我下面代码中的ai等价于我上面分析中的gcd(ai,n),别理解错了;

    int n,m,ans,a[55];
    int gcd(int x,int y){
        if(y==0)return x;
        return gcd(y,x%y);
    }
    int phi(int x){//求欧拉函数的模板
        int y=x;
        for(int i=2;i*i<=x;i++)
            if(x%i==0){
    	    	y=y/i*(i-1);
                while(x%i==0)x/=i;
            }
        if(x>1)y=y/x*(x-1);
        return y;
    }
    void solve(int x){
        for(int i=1;i<=m;i++)
    		if(x%a[i]==0)return;
        ans+=phi(n/x);
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++)
    		a[i]=gcd(read(),n);
    //这里a[i]直接记录的就是
    //同学i能够经过所有编号是a[i]倍数的格子
        for(int i=1;i*i<=n;i++){
    		if(n%i==0){//枚举n的约数i
    	    	solve(i);
    	    	if(i*i<n)solve(n/i);
    //与i相对的n的另一个约数
    		}
        }
        printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    Ant属性文件
    使用numpy处理数组
    机器学习实战之决策树(一)
    列表去掉重复元素
    cv2.putText,cv2.rectangle方法
    sklearn 中文文档
    numpy delete方法
    MATLAB ~的用法
    MATLAB 基础
    Python 遍历目录下的子目录和文件
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10385397.html
Copyright © 2011-2022 走看看