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}\lfloor\frac{A}{x}\rfloor\lfloor\frac{B}{y}\rfloor\lfloor\frac{C}{z}\rfloor\)

這裏記\(F_A(x)=\sum_{x|i}\lfloor\frac{A}{i}\rfloor\),\(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)\neq 0,\mu(b)\neq 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\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章