bzoj5332&loj2565 [Sdoi2018]旧试题

http://www.elijahqi.win/archives/3492
题目地址https://loj.ac/problem/2565

https://www.lydsy.com/JudgeOnline/problem.php?id=5332
首先知道结论
原题所求可以转化为
i = 1 A j = 1 B k = 1 C x | i y | j z | k [ g c d ( x , y ) = 1 ] [ g c d ( x , z ) = 1 ] [ g c d ( y , z ) = 1 ]
x = 1 A y = 1 B z = 1 C [ g c d ( x , y ) = 1 ] [ g c d ( x , z ) = 1 ] [ g c d ( y , z ) = 1 ] A x B y C z
针对每个gcd莫比乌斯反演
x = 1 A y = 1 B z = 1 C i | x , i | y μ ( i ) j | x , j | z μ ( j ) k | y , k | z μ ( k ) A x B y C z
i = 1 A j = 1 B k = 1 C μ ( i ) μ ( j ) μ ( k ) i | x , j | x A x i | y , k | y B y j | z , k | z C z
后面这个带下去整符号的东西我们可以考虑n log(n)预处理 设 f n ( i ) = i | d n n d
那么因为后面的东西是 i | x , j | x 所以直接给他换成lcm的倍数即可
然后考虑这直接暴力是n^3但是显然当f函数的i>n的时候是0 所以我们考虑如何求解
首先把i,j,k都相同的枚举 算答案再算两两相同的答案 n=max(A,B,C);
设点x,y 只有当他们的lcm< n的时候把他们加入然后给无向图定向 使得点度小的往大的连如果相同编号小->大
这样保证每个点出度是sqrt(n)
然后最后再去暴力枚举三元环即可 因为顺序问题 分六种情况讨论
前面的枚举两两相同的采取枚举lcm的方式可以使得复杂度是 n l o g ( n ) 2

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define fi first
#define se second
#define ll long long
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e5+10;
const int mod=1e9+7;
inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
ll ans,fa[N],fb[N],fc[N];bool not_prime[N];vector<pa> eg[N];
int T,prime[N],tot,mu[N],A,B,C,n,sa[N],sb[N],sc[N],d[N];
inline void init(){
    mu[1]=1;
    for (int i=2;i<=1e5;++i){
        if (!not_prime[i]) prime[++tot]=i,mu[i]=-1;
        for (int j=1;prime[j]*i<=1e5;++j){
            not_prime[prime[j]*i]=1;
            if (i%prime[j]==0){
                mu[prime[j]*i]=0;break;
            }else mu[prime[j]*i]=-mu[i];
        }
    }
}
struct node{
    int x,y,z;
}data[N*10];
inline void insert1(int x,int y,int z){eg[x].push_back(mp(y,z));}
inline bool check(int i){
    int x=data[i].x,y=data[i].y;
    return d[x]==d[y]?x<y:d[x]<d[y];
}
int main(){
    freopen("bzoj5332.in","r",stdin);
    T=read();init();
    while(T--){
        A=read();B=read();C=read();n=max(A,max(B,C));tot=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) if(mu[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;j*i<=n;++j){
                if (!mu[i*j]) continue;
                for (int k=1;k*i*j<=n;++k){
                    if(k==j||gcd(k,j)!=1||!mu[i*k]) continue;
                    int x=i*j,y=i*k,z=i*j*k,tmp=mu[x]*mu[x]*mu[y];
                    ans+=tmp*fa[x]*fb[z]*fc[z];
                    ans+=tmp*fb[x]*fa[z]*fc[z];
                    ans+=tmp*fc[x]*fa[z]*fb[z];
                    if(j>k) continue;data[++tot]=(node){x,y,z};++d[x];++d[y];
                }
            }
        }
        for (int i=1;i<=tot;++i) if (check(i)) insert1(data[i].x,data[i].y,data[i].z);
        else insert1(data[i].y,data[i].x,data[i].z);
        for (int i=1;i<=n;++i){
            for (int j=0;j<eg[i].size();++j){
                int y=eg[i][j].fi,z=eg[i][j].se;
                sa[y]=fa[z];sb[y]=fb[z];sc[y]=fc[z];
            }
            for (int j=0;j<eg[i].size();++j){
                int y=eg[i][j].fi,w1=eg[i][j].se;
                for (int k=0;k<eg[y].size();++k){
                    int z=eg[y][k].fi,w2=eg[y][k].se,x=i,tmp=mu[x]*mu[y]*mu[z];
                    ans+=tmp*fa[w1]*fb[w2]*sc[z];
                    ans+=tmp*fa[w1]*fc[w2]*sb[z];
                    ans+=tmp*fb[w1]*fc[w2]*sa[z];
                    ans+=tmp*fb[w1]*fa[w2]*sc[z];
                    ans+=tmp*fc[w1]*fb[w2]*sa[z];
                    ans+=tmp*fc[w1]*fa[w2]*sb[z];
                }
            }
            for (int j=0;j<eg[i].size();++j){
                int y=eg[i][j].fi;sa[y]=sb[y]=sc[y]=0;
            }
        }
        printf("%lld\n",ans%mod);
        for (int i=1;i<=n;++i) eg[i].clear(),d[i]=fa[i]=fb[i]=fc[i]=0;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/elijahqi/article/details/80462322