zoukankan      html  css  js  c++  java
  • luogu P4619 [SDOI2018]旧试题

    luogu

    先考虑(d(i,j,k))是啥,首先会有(d(i,j)=sum_{x|i}sum_{y|j}[gcd(x,y)=1]),可以推广得到(d(i,j,k)=sum_{x|i}sum_{y|j}sum_{z|k}[gcd(x,y)=1][gcd(y,z)=1][gcd(x,z)=1]),然后开始化式子

    (sum_{i=1}^{A}sum_{j=1}^{B}sum_{k=1}^{C}sum_{x|i}sum_{y|j}sum_{z|k}[gcd(x,y)=1][gcd(y,z)=1][gcd(x,z)=1])

    (sum_{i=1}^{A}sum_{j=1}^{B}sum_{k=1}^{C}sum_{x|i}sum_{y|j}sum_{z|k}sum_{a|x,a|y}mu(a)sum_{b|y,b|z}mu(b)sum_{c|z,c|x}mu(c))

    (sum_{a=1}^{min(A,B)}sum_{b=1}^{min(B,C)}sum_{c=1}^{min(C,A)}mu(a)mu(b)mu(c)sum_{mathrm{lcm}(c,a)|x}sum_{mathrm{lcm}(a,b)|y}sum_{mathrm{lcm}(b,c)|z}lfloorfrac{A}{x} floorlfloorfrac{B}{y} floorlfloorfrac{C}{z} floor)

    这里记(F_A(x)=sum_{x|i}lfloorfrac{A}{i} floor),(F_B(x),F_C(x))同理,可得

    (sum_{a=1}^{min(A,B)}sum_{b=1}^{min(B,C)}sum_{c=1}^{min(C,A)}mu(a)mu(b)mu(c)F_A(mathrm{lcm}(c,a))F_B(mathrm{lcm}(a,b))F_C(mathrm{lcm}(b,c)))

    到这个时候就可以讨论了,首先是(a=b=c)的情况,可以做到(O(n))统计;然后是(abc)中两个相等且另外一个不相等,以及三个都不相等的情况.答案的这个形式就是枚举三个不同的数,然后考虑他们两两之间的贡献,可以联想到建图,连上所有的((a,b,mathrm{lcm}(a,b)))即可套三元环计数.然后我们显然只用考虑(mu(a) eq 0,mu(b) eq 0,mathrm{lcm}(a,b)le max{A,B,C})的边,可以发现这样的边只有约(8*10^5)条,所以如果是(abc)中两个相等且和另外一个不相等的情况,就是一次枚举每条边,然后枚举这条边会对应的(aab,abb,aac,acc,bbc,bcc)六种情况;如果是(abc)都不相等,那么对应到图上就是枚举一个三元环,所以使用三元环计数即可,枚举三元环复杂度(O(|E|^{1.5})),再讨论这三个点分别(abc)中的哪个来统计答案

    然后这题较卡常,首先(F_A,F_B,F_C)可以(O(nlogn))预处理;然后是建图问题,因为(mathrm{lcm}(a,b)=gcd(a,b)frac{a}{gcd(a,b)}frac{b}{gcd(a,b)}),那么只要枚举(gcd(a,b)frac{a}{gcd(a,b)}frac{b}{gcd(a,b)})并且保证他们的乘积(le max{A,B,C}),可以发现这个复杂度类似调和极数,为(O(nlog^2n));还有就是能并在一起计算的式子最好并在一起

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    
    using namespace std;
    const int N=1e5+10,M=N*10,mod=1e9+7;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;
    }
    /*int to[M],nt[M],w[M],hd[N],tot=1;
    void adde(int x,int y,int z){++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;}*/
    void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int prm[N],pp[N],f[N],g[N],h[N],mu[N],tt,nm[N],tn,id[N],dg[N],vs[N],te;
    int n,a,b,c,ans;
    void inii(int *f,int nn)
    {
        memset(f,0,sizeof(int)*(n+1));
        for(int i=1;i<=nn;++i)
    	for(int j=1;i*j<=nn;++j)
    	    ad(f[i],nn/(i*j));
    }
    struct node{int x,y,z;}ee[M];
    vector<node> gg[N];
    vector<node>::iterator i1,i2;
    
    int main()
    {
    ///wdnmd
        mu[1]=1;
        for(int i=2;i<=N-5;++i)
        {
        	if(!pp[i]) pp[i]=1,prm[++tt]=i,mu[i]=-1;
        	for(int j=1;i*prm[j]<=N-5;++j)
        	{
        	    if(i%prm[j]==0){pp[i*prm[j]]=pp[i]+1;break;}
        	    pp[i*prm[j]]=1,mu[i*prm[j]]=-mu[i];
        	}
        }
        for(int i=1;i<=N-5;++i)
    	if(mu[i]) nm[++tn]=i,id[i]=tn;
        int lt=tn,T=rd();
        while(T--)
        {
        	a=rd(),b=rd(),c=rd();
        	n=max(max(a,b),c);
        	inii(f,a),inii(g,b),inii(h,c);
        	tn=lt;
        	while(nm[tn]>n) --tn;
        	te=0;
        	memset(dg,0,sizeof(int)*(n+1))/*,memset(hd,0,sizeof(int)*(n+1)),tot=1*/;
        	for(int d=1;d<=n;++d)
        	    for(int i=1;1ll*i*d<=n;++i)
        	    	for(int j=i+1;1ll*i*j*d<=n;++j)
        	    	    if(mu[i*d]&&mu[j*d]&&gcd(i,j)==1) ++dg[id[i*d]],++dg[id[j*d]],ee[++te]=(node){id[i*d],id[j*d],i*j*d};
        	for(int i=1;i<=tn;++i) gg[i].clear();
        	for(int i=1;i<=te;++i)
        	{
        	    int x=ee[i].x,y=ee[i].y,z=ee[i].z;
        	    if(dg[x]>dg[y]) swap(x,y);
        	    gg[x].push_back((node){i,y,z});
        	}
        	ans=0;
        	for(int x=1;x<=tn;++x)
        	{
        	    for(i1=gg[x].begin();i1!=gg[x].end();++i1)
        	    {
            		int i=(*i1).x,y=(*i1).y,xx=nm[x],yy=nm[y],w=(*i1).z;
            		vs[y]=i;
            		int nw=(1ll*f[xx]*g[w]%mod*h[w]+1ll*f[w]*g[xx]%mod*h[w]+1ll*f[w]*g[w]%mod*h[xx])%mod;
            		ad(ans,(~(mu[xx]*mu[xx]*mu[yy])?nw:mod-nw));
            		nw=(1ll*f[yy]*g[w]%mod*h[w]+1ll*f[w]*g[yy]%mod*h[w]+1ll*f[w]*g[w]%mod*h[yy])%mod;
            		ad(ans,(~(mu[xx]*mu[yy]*mu[yy])?nw:mod-nw));
        	    }
        	    for(i1=gg[x].begin();i1!=gg[x].end();++i1)
        	    {
            		int i=(*i1).x,y=(*i1).y;
            		for(i2=gg[y].begin();i2!=gg[y].end();++i2)
            		{
            		    int j=(*i2).x,z=(*i2).y;
            		    if(vs[z])
            		    {
                			int k=vs[z],w1=ee[i].z,w2=ee[j].z,w3=ee[k].z;
                			int nw=(1ll*f[w1]*g[w2]%mod*h[w3]+1ll*f[w1]*g[w3]%mod*h[w2]+1ll*f[w2]*g[w1]%mod*h[w3]+1ll*f[w2]*g[w3]%mod*h[w1]+1ll*f[w3]*g[w1]%mod*h[w2]+1ll*f[w3]*g[w2]%mod*h[w1])%mod;
                			ad(ans,(~(mu[nm[x]]*mu[nm[y]]*mu[nm[z]])?nw:mod-nw));
            		    }
            		}
                }
            	for(i1=gg[x].begin();i1!=gg[x].end();++i1) vs[(*i1).y]=0;
        	}
        	for(int i=1;i<=tn;++i)
        	{
        	    int nw=1ll*f[nm[i]]*g[nm[i]]%mod*h[nm[i]]%mod;
        	    ad(ans,(~(mu[nm[i]]*mu[nm[i]]*mu[nm[i]])?nw:mod-nw));
        	}
        	printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    jvm相关参数
    fdisk磁盘分区与挂载
    解决 Redis 只读不可写的问题
    虚拟机linux系统明明已经安装了ubuntu,但是每次重新进入就又是选择安装界面
    linux下更改MySQL数据库存储路径
    消除过期的引用对象
    java避免创建不必要的对象
    Oracle minus用法详解及应用实例
    Mapreduce详解Shuffle过程
    Leet Code 7.整数反转
  • 原文地址:https://www.cnblogs.com/smyjr/p/12373372.html
Copyright © 2011-2022 走看看