• LOJ2565. 「SDOI2018」旧试题


    给出(A,B,C),求(sum_{i=1}^{A}sum_{j=1}^{B}sum_{k=1}^C sigma_0(ijk))

    (sigma_0(n))表示(n)的约数个数。

    (A,B,Cle 10^5)


    结论:(sigma_0(ijk)=sum_{a|i}sum_{b|j}sum_{c|k}[bperp c][a perp c][a perp b])

    证明类比只有两个数的情况。

    接下来推式子,三项东西同步推,得到:(sum_isum_jsum_kmu(i)mu(j)mu(k)f(A,[j,k])f(B,[i,k])f(C,[i,j]))

    其中(f(n,d)=sum_{d|i}frac{n}{i})。暴力求时间(O(nln n))

    神仙转化:建图,找三元环((i,j,k))

    建图的时候要求(lcm)不超过(n)。于是连出来的边实际上只有不到(8*10^5)条。

    找三元环:求出每个点的度数,把边定向为从大度数到小度数。枚举某个点(u),先枚举((u,w)in E)(w)打上标记,再枚举((u,v),(v,w)in E),若(w)有标记则找到一个三元环。

    时间复杂度:其实相当于对于((u,v)in E),给(out_v)求和。如果(deg_vle sqrt m),则(out_vle sqrt m),总共(O(msqrt m));如果(deg_vge sqrt m),这样的(v)(u)不超过(sqrt m)个,于是(out_v)最多被贡献(sqrt m)次,总共也是(O(msqrt m))

    还有更加神仙的不用找三元环的方法当然我不会……


    using namespace std;
    #include <bits/stdc++.h>
    #define N 100005
    #define ll long long
    #define mo 1000000007
    int gcd(int a,int b){
    	int k;
    	while (b)
    		k=a%b,a=b,b=k;
    	return a;
    }
    int lcm(int a,int b){
    //	assert((ll)a/gcd(a,b)*b<=100005);
    	return a/gcd(a,b)*b;
    }
    int A[3],n;
    int p[N],np;
    bool inp[N];
    int mu[N],mnp[N];
    void initp(int n){
    	mu[1]=1;
    	for (int i=2;i<=n;++i){
    		if (!inp[i])
    			p[++np]=i,mu[i]=-1,mnp[i]=i;
    		for (int j=1;j<=np && i*p[j]<=n;++j){
    			inp[i*p[j]]=1;
    			mnp[i*p[j]]=p[j];
    			if (i%p[j]==0)
    				break;
    			mu[i*p[j]]=-mu[i];
    		}
    	}
    }
    int f[3][N];
    void initf(int g[],int n){
    	for (int i=1;i<=n;++i){
    		ll sum=0;
    		for (int j=1;i*j<=n;++j)
    			sum+=n/(i*j);
    		g[i]=sum%mo;
    	}
    }
    int deg[N];
    struct EDGE{
    	int to,w;
    	EDGE *las;
    } e[1000000];
    int ne;
    EDGE *last[N];
    void link(int u,int v,int w){
    	e[ne]={v,w,last[u]};
    	last[u]=e+ne++;
    }
    struct edge{int u,v,w;} ed[1000000];
    int q[N],re[N],totv,tote;
    bool cmpq(int x,int y){return deg[x]>deg[y];}
    ll ans;
    void calc(int a){
    	ll s=(ll)f[0][a]*f[1][a]%mo*f[2][a]%mo;
    	ans+=mu[a]*s;
    }
    void calc(int a,int b,int ab){
    	ll s=0;
    	s+=(ll)f[0][b]*f[1][ab]%mo*f[2][ab];
    	s+=(ll)f[0][ab]*f[1][b]%mo*f[2][ab];
    	s+=(ll)f[0][ab]*f[1][ab]%mo*f[2][b];
    	s%=mo;
    	ans+=mu[a]*s;
    }
    void calc(int a,int b,int c,int ab,int ac,int bc){
    	ll s=0;
    	s+=(ll)f[0][ab]*f[1][ac]%mo*f[2][bc];
    	s+=(ll)f[0][ab]*f[2][ac]%mo*f[1][bc];
    	s+=(ll)f[1][ab]*f[0][ac]%mo*f[2][bc];
    	s+=(ll)f[1][ab]*f[2][ac]%mo*f[0][bc];
    	s+=(ll)f[2][ab]*f[0][ac]%mo*f[1][bc];
    	s+=(ll)f[2][ab]*f[1][ac]%mo*f[0][bc];
    	s%=mo;
    	ans+=mu[a]*mu[b]*mu[c]*s;
    }
    int W,d[N],z[N],dz[N],cp;
    void divide(int x){
    	cp=0;
    	while (x!=1){
    		d[++cp]=mnp[x];
    		z[cp]=0,dz[cp]=1;
    		while (x%d[cp]==0)
    			z[cp]++,x/=d[cp],dz[cp]*=d[cp];
    	}
    }
    void find(int k,int u,int v){
    	if (k>cp){
    		if (u<v && mu[u] && mu[v]){
    			ed[++tote]={u,v,W};
    			deg[u]++,deg[v]++;
    		}
    		return;
    	}
    	int pro=1;
    	for (int i=0;i<z[k];++i,pro*=d[k]){
    		find(k+1,u*pro,v*dz[k]);
    		find(k+1,u*dz[k],v*pro);
    	}
    	find(k+1,u*dz[k],v*dz[k]);
    }
    void work(){
    	memset(deg,0,sizeof(int)*(n+1));
    	totv=0,tote=0;
    	for (int i=1;i<=n;++i){
    		W=i;
    		divide(i);
    		find(1,1,1);
    	}
    	for (int i=1;i<=n;++i)
    		if (mu[i])
    			q[++totv]=i;
    	sort(q+1,q+totv+1,cmpq);
    	for (int i=1;i<=totv;++i)
    		re[q[i]]=i;
    	ne=0;
    	memset(last,0,sizeof(EDGE*)*(n+1));
    	for (int i=1;i<=tote;++i){
    		int u=ed[i].u,v=ed[i].v;
    		if (re[u]>re[v])
    			swap(u,v);
    		link(u,v,ed[i].w);
    	}
    	static int bz[N];
    	for (int i=1;i<=totv;++i){
    		int u=q[i];
    		for (EDGE *ei=last[u];ei;ei=ei->las)
    			bz[ei->to]=ei->w;
    		for (EDGE *ei=last[u];ei;ei=ei->las){
    			calc(u,ei->to,ei->w);
    			calc(ei->to,u,ei->w);
    			for (EDGE *ej=last[ei->to];ej;ej=ej->las)
    				if (bz[ej->to])
    					calc(u,ei->to,ej->to,ei->w,ej->w,bz[ej->to]);
    		}
    		for (EDGE *ei=last[u];ei;ei=ei->las)
    			bz[ei->to]=0;
    		calc(u);
    	}
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    	initp(100000);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d%d%d",&A[0],&A[1],&A[2]);
    		sort(A,A+3);
    		n=A[2];
    		for (int k=0;k<3;++k){
    			memset(f[k],0,sizeof(int)*(n+1));
    			initf(f[k],A[k]);
    		}
    		ans=0;
    		work();	
    		ans=(ans%mo+mo)%mo;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [Unit Testing] Test Mongoose model
    2021CSPJ 组初级真题答案及全部解析
    AcWing 1097. 池塘计数
    AcWing 1076. 迷宫问题
    AcWing 1107 魔板
    K进制试题解析
    AcWing 1100. 抓住那头牛
    AcWing 1106. 山峰和山谷
    AcWing 188. 武士风度的牛
    AcWing 173. 矩阵距离
  • 原文地址:https://www.cnblogs.com/jz-597/p/14294993.html
Copyright © 2020-2023  润新知