zoukankan      html  css  js  c++  java
  • 【LGP5176】公约数

    题目

    老年选手啥都不想推只能搞个杜教筛了

    这个式子长得好吓人啊,所以我们唯一分解之后来考虑这道题

    (i,j,k)分别是(p^a,p^b,p^c),至于到底谁是谁并不重要,我们不妨假设(aleq bleq c)

    那么(gcd(i imes j,j imes k,k imes i)=min{p^{a+b},p^{a+c},p^{b+c}}=p^{a+b})

    (gcd(i,j,k)=min{p^a,p^b,p^c}=p^a)

    也就是前面两个柿子乘起来是(p^{2a+b})

    我们把后面的柿子分母通分

    [frac{(i,j)^2+(j,k)^2+(k,i)^2}{(i,j)(j,k)(k,i)} ]

    我们发现分母上还是等于(p^{2a+b}),因为(p^a)跟另外两个组合得到的(gcd)都是(p^a)(p^b)(p^{c})(gcd)(p^b),所以分母上是(p^{2a+b})

    和外面一约分,没了

    显然唯一分解之后各个质数次幂是相互独立的,于是我们现在可以得出结论,我们要求的就是

    [sum_{i=1}^nsum_{j=1}^msum_{k=1}^p(i,j)^2+(j,k)^2+(k,i)^2 ]

    显然可以拆成

    [p imes sum_{i=1}^nsum_{j=1}^m(i,j)^2+n imes sum_{j=1}^msum_{k=1}^p(j,k)^2+m imes sum_{i=1}^nsum_{k=1}^p(k,i)^2 ]

    套路反演我们可以得到我们要求的东西实际上是

    [sum_{i=1}^nleft lfloor frac{n}{i} ight floorleft lfloor frac{m}{i} ight floorsum_{d|i}mu(frac{i}{d})d^2 ]

    后面的东西线筛也很好推,但是老年选手并不想动脑子了

    发现后面的柿子是(id^2 imes mu),我们直接杜教筛卷上(1)就变成(id^2)了,(id^2)的前缀和自然是(frac{n(n+1)(2n+1)}{6})

    这样是(O(n^{frac{3}{4}}))的,但是我们暴力调合级数处理一些,就能跑的很快了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int T;
    const int I6=166666668;
    const int mod=1e9+7;
    const int maxn=1e6+1;
    int p[maxn>>1],is[maxn],mu[maxn];
    int f[20000005],vis[20000005];
    inline int calc(int x) {return 1ll*x*(x+1)%mod*(x+x+1)%mod*I6%mod;}
    inline int solve(int x) {
    	if(vis[x]) return f[x];
    	vis[x]=1;int ans=calc(x);
    	for(re int l=2,r;l<=x;l=r+1) {
    		r=x/(x/l);
    		ans=(ans-1ll*solve(x/l)*(r-l+1)%mod+mod)%mod;
    	}
    	return f[x]=ans;
    }
    inline int work(int n,int m) {
    	if(n>m) std::swap(n,m);
    	int ans=0;
    	for(re int l=1,r;l<=n;l=r+1) {
    		r=min(n/(n/l),m/(m/l));
    		ans=(ans+1ll*(n/l)*(m/l)%mod*(solve(r)-solve(l-1)+mod)%mod)%mod;
    	}
    	return ans;
    }
    int main() {
    	T=read();is[1]=mu[1]=1;
    	for(re int i=2;i<maxn;i++) {
    		if(!is[i]) p[++p[0]]=i,mu[i]=-1;
    		for(re int j=1;j<=p[0]&&p[j]*i<maxn;j++) {
    			is[p[j]*i]=1;if(i%p[j]==0) break;mu[p[j]*i]=-1*mu[i];
    		}
    	}
    	for(re int i=1;i<maxn;i++)
    		for(re int j=i;j<maxn;j+=i) {
    			if(!mu[j/i]) continue;
    			if(mu[j/i]<0) f[j]=(f[j]-1ll*i*i%mod+mod)%mod;
    				else f[j]=(f[j]+1ll*i*i)%mod;
    		}
    	for(re int i=1;i<maxn;i++)
    		vis[i]=1,f[i]=(f[i]+f[i-1])%mod;
    	while(T--) {
    		int n=read(),m=read(),p=read();
    		int tmp=1ll*work(n,m)*p%mod+1ll*work(m,p)*n%mod;tmp%=mod;
    		tmp=(tmp+1ll*work(n,p)*m%mod)%mod;
    		printf("%d
    ",tmp%mod);
    	}
    }
    
  • 相关阅读:
    【英语】Bingo口语笔记(40)
    【英语】Bingo口语笔记(38)
    【Python系统学习】基础篇
    【英语】Bingo口语笔记(37)
    [转]linux下ulimit命令详解
    【转】linux read 用法
    【转】Linux下使用locale命令设置语言环境
    【转】基于linux下的变量声明declare的用法
    [转]Linux中set,env和export这三个命令的区别
    linux下echo命令详解(转)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10777649.html
Copyright © 2011-2022 走看看