bzoj5332/loj2565 [Sdoi2018]旧试题(Mobius反演+图论)

x = 1 A y = 1 B z = 1 C d ( x y z )
类似这道题的结论,我们有
d ( x y z ) = i | x j | y k | z [ ( i , j ) == 1 ] [ ( j , k ) == 1 ] [ ( i , k ) == 1 ]
于是带进去,就是求

x = 1 A y = 1 B z = 1 C i | x j | y k | z [ ( i , j ) == 1 ] [ ( j , k ) == 1 ] [ ( i , k ) == 1 ]

i = 1 A j = 1 B k = 1 C [ ( i , j ) == 1 ] [ ( j , k ) == 1 ] [ ( i , k ) == 1 ] A i B j C k

莫比乌斯反演一下就是:

i = 1 A j = 1 B k = 1 C u | i u | j μ ( u ) v | j v | k μ ( v ) w | i w | k μ ( w ) A i B j C k

u = 1 A v = 1 B w = 1 C μ ( u ) μ ( v ) μ ( w ) u | i w | i A i u | j v | j B j v | k w | k C k

f x ( n ) = n | d x d ,这个东西显然可以nlogn预处理
A n s = u = 1 A v = 1 B w = 1 C μ ( u ) μ ( v ) μ ( w ) f A ( l c m ( u , w ) ) f B ( l c m ( u , v ) ) f C ( l c m ( v , w ) )

我们注意到若n>x,那么 f x ( n ) = 0
令n=max(A,B,C)
那么只有当lcm(x,y)<=n时 f x ( n ) 才有值。
因此我们对mu[x]!=0的点x建无向图。如果lcm(x,y)<=n就建边,边权为lcm(x,y)
对于所有三元环算贡献即可。建图要枚举lcm来建… O ( n l o g 2 n )
这样的话点数最多60794,边数最多760741.
但是你需要优美的枚举三元环才能通(卡)过!

比如去掉自环,把非三个不同点构成的三元环在外面枚举了。
比如ans最后再取模,不会爆ll。
比如给边定向,把无向图变成有向图。(度数小的向度数大的连边,这样才可以保证复杂度 O ( m m )
这样的话一个三元环只会被枚举到一次,即你枚举了无序三元组,你需要把六种情况全都统计了。
然后你枚举一个点x,再枚举一个它的出点y,再枚举一个出点z就好啦。

复杂度大概 O ( ( n l o g 2 n ) 1.5 )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define mod 1000000007
#define pa pair<int,int>
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,prime[N>>3],tot=0,mu[N],m,du[N];
ll fa[N],fb[N],fc[N],sa[N],sb[N],sc[N],ans=0;
bool notprime[N];
struct E{
    int u,v,w;
    bool cmp(){return du[u]<du[v]||du[u]==du[v]&&u<v;}
}e[N*20];
vector<pa>eg[N];
inline void add(int x,int y,int w){eg[x].push_back(make_pair(y,w));}
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline void init(){
    notprime[1]=1;mu[1]=1;
    for(int i=2;i<=1e5;++i){
        if(!notprime[i]) prime[++tot]=i,mu[i]=-1;
        for(int j=1;prime[j]*i<=1e5;++j){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0){
                mu[prime[j]*i]=0;break;
            }mu[prime[j]*i]=-mu[i];
        }
    }
}
int main(){
//  freopen("a.in","r",stdin);
    int tst=read();init();
    while(tst--){
        int A=read(),B=read(),C=read();n=max(A,max(B,C));m=0;ans=0;
        for(int i=1;i<=n;++i)
            for(int j=i;j<=n;j+=i)
                fa[i]+=A/j,fb[i]+=B/j,fc[i]+=C/j;
        for(int i=1;i<=n;++i) ans+=mu[i]*mu[i]*mu[i]*fa[i]*fb[i]*fc[i];
        for(int i=1;i<=n;++i)
            for(int j=1;i*j<=n;++j){
                if(!mu[i*j]) continue;
                for(int k=1;i*j*k<=n;++k){
                    if(!mu[i*k]||k==j||gcd(j,k)!=1) continue;
                    int u=i*j,v=i*k,w=i*j*k,tmp=mu[u]*mu[u]*mu[v];
                    ans+=tmp*fa[u]*fb[w]*fc[w];
                    ans+=tmp*fb[u]*fa[w]*fc[w];
                    ans+=tmp*fc[u]*fa[w]*fb[w];
                    if(k<j) continue;e[++m].u=u;e[m].v=v;e[m].w=w;
                    du[u]++;du[v]++;
                }
            }
        for(int i=1;i<=m;++i) if(e[i].cmp()) add(e[i].u,e[i].v,e[i].w);
        else add(e[i].v,e[i].u,e[i].w);
        for(int x=1;x<=n;++x){
            for(int i=0;i<eg[x].size();++i){
                int y=eg[x][i].first,w=eg[x][i].second;
                sa[y]=fa[w];sb[y]=fb[w];sc[y]=fc[w];
            }for(int i=0;i<eg[x].size();++i){
                int y=eg[x][i].first,w1=eg[x][i].second;
                for(int j=0;j<eg[y].size();++j){
                    int z=eg[y][j].first,w2=eg[y][j].second;
                    int tmp=mu[x]*mu[y]*mu[z];
                    ans+=tmp*fa[w1]*fb[w2]*sc[z];
                    ans+=tmp*fa[w1]*sb[z]*fc[w2];
                    ans+=tmp*fa[w2]*fb[w1]*sc[z];
                    ans+=tmp*fa[w2]*sb[z]*fc[w1];
                    ans+=tmp*sa[z]*fb[w1]*fc[w2];
                    ans+=tmp*sa[z]*fb[w2]*fc[w1];
                }
            }for(int i=0;i<eg[x].size();++i){
                int y=eg[x][i].first,w=eg[x][i].second;
                sa[y]=sb[y]=sc[y]=0;
            }
        }printf("%lld\n",ans%mod);
        for(int i=1;i<=n;++i) fa[i]=fb[i]=fc[i]=0,eg[i].clear(),du[i]=0;
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80435307