zoukankan      html  css  js  c++  java
  • 最大公约数,题解

    题目:

      

     

    分析:

      题意是比较简洁的,我们先不考虑取整的问题(精度问题和取mod问题也先放放),这题应该怎么做.

      首先m很小,我们从m下手下手,首先观察f(i,j)会发现f(i+j,j)=f(i,j),首先我们要知道:(p,q)=1,那么(p+q,q)=1,证明如下:

      设存在p,q互质且p+q,q不互质,那么就有p+q=k1*x,q=k2*x(x!=1),那么有p=(k1-k2)x,不与q互质,与假设矛盾,故原式得证.

      然后(i,j)=(i+j,j)是类似的,设i=px,j=qx,p,q互质,那么(i+j,j)=(px+qx,qx)=x(p+q,q)=x,所以(i,j)=(i+j,j)

      于是原函数里的x是相等的,对于c,第一次操作将会把x变成j,y变成i%j,之后操作就相同了,自然也是相等的

      于是有f(i,j)=f(i+j,j)

      于是:i*j/f(i,j)+(i+j)*j/f(i+j,j)+(i+2*j)*j/f(i+2*j,j)+...+(i+k*j)*j/f(i+k*j,j)=((i*j)+(i*j+j*j)+(i*j+2*j*j)+...+(i*j+k*j*j))/f(i,j)(i<=j)

      发现上面是等差,下面是一个可以算的数,于是我们就可以通过一次求和公式把n的一堆数字加进来,对于每一个j我们只需要遍历一个j的完全剩余系,求出和来就可以了,复杂度m*m*logm(log求f函数)

      然后如何取整,由于是对里面取整,先算出来再取很可能进位不该进位的1,所以我们考虑换一种办法,现在不能以j分界了,但是我们想想,出现小数的原因是c,如果没有c,i*j/(x*x)不会是小数,但是我们如果c个c个的j去增加,那么取整之后仍然是等差(相当于舍掉的数相同),那么我们就可以这样去处理,发现复杂度还是m*m*logm,没有问题.

      代码:

      

    #include <cstdio>
    long long mod;
    long long gcd1;
    long long gcd2(long long a,long long b){//求gcd
        return b?gcd2(b,a%b):a;
    }
    long long gcdc(long long x,long long y){//求c
        long long t;
        long long c=0;
        while(y>0){
            c++;
            t=x%y;
            x=y;
            y=t;
        }
        return c;
    }
    const int maxn=666+10;
    long long gdc[maxn][maxn];
    long long gd2[maxn][maxn];
    int main(){
        int t;
        scanf("%d",&t);
        for(int i=1;i<=666;i++)
            for(int j=1;j<=666;j++){
                gdc[i][j]=gcdc((long long)i,(long long)j);
                gd2[i][j]=gcd2((long long)i,(long long)j);
            }
        for(int jsjs=1;jsjs<=t;jsjs++){
            long long n,m,ans=0;
            scanf("%lld%lld%lld",&n,&m,&mod);
            for(int i=1;i<=m;i++)
                for(int j=1;j<=i;j++){
                    if(j>n)
                        break;
                    long long c=gdc[j][i];
                    long long gd=gd2[j][i];
                    long long f=c*gd*gd;//f函数
                    for(int k=0;k<c;k++){
                        if(j+k*i>n)
                            break;
                        long long sx=(j+k*i)*i/f//首项;
                        long long xs=(n-j-k*i)/(c*i)+1;//项数
                        long long gc=c*i*i/f;//公差
                        ans+=sx*xs+xs*(xs-1)/2%mod*gc;//数列求和
                        ans%=mod;
                    }
                }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    【实战】一次简单的js接口漏洞挖掘
    【实战】Location 302跳转 + CRLF 场景下的XSS
    【实战】权限绕过小结
    【实战】简单的API接口FUZZ小案例
    【实战】一次有趣的逻辑漏洞挖掘
    【实战】一个简单的SQL注入绕过
    【实战】springboot actuator未授权访问之trace接口泄漏敏感信息
    【实战】springboot actuator未授权访问之heapdump敏感信息提取
    层次分析法AHP
    pyppeteer(1)
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12990683.html
Copyright © 2011-2022 走看看