[SDOI2018] 旧试题

推狮子的部分

\[ \sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sigma(ijk) =\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sum_{x|i}\sum_{y|j}\sum_{z|k}\epsilon(\gcd(x,y))\epsilon(\gcd(y,z))\epsilon(\gcd(x,z))\\ =\sum_{i=1}^A\sum_{x|i}\sum_{j=1}^B\sum_{y|j}\sum_{k=1}^C\sum_{z|k}\epsilon(\gcd(x,y))\epsilon(\gcd(y,z))\epsilon(\gcd(x,z))\\ =\sum_{x=1}^A\lfloor\frac{A}{x}\rfloor\sum_{y=1}^B\lfloor\frac{B}{y}\rfloor\sum_{z=1}^C\lfloor\frac{C}{z}\rfloor\epsilon(\gcd(x,y))\epsilon(\gcd(y,z))\epsilon(\gcd(x,z))\\ =\sum_{x=1}^A\lfloor\frac{A}{x}\rfloor\sum_{y=1}^B\lfloor\frac{B}{y}\rfloor\sum_{z=1}^C\lfloor\frac{C}{z}\rfloor\sum_{d|x,d|y}\mu(d)\sum_{p|y,p|z}\mu(p)\sum_{q|x,q|z}\mu(q)\\ =\sum_{d=1}^{\min(A,B)}\mu(d)\sum_{p=1}^{\min(B,C)}\mu(p)\sum_{q=1}^{\min(A,C)}\mu(q)\sum_{d|x,q|x}^A\lfloor\frac{A}{x}\rfloor\sum_{d|y,p|y}^B\lfloor\frac{B}{y}\rfloor\sum_{p|z,q|z}^C\lfloor\frac{C}{z}\rfloor\\ =\sum_{d=1}^{\min(A,B)}\mu(d)\sum_{p=1}^{\min(B,C)}\mu(p)\sum_{q=1}^{\min(A,C)}\mu(q)\sum_{lcm(d,q)|x}^A\lfloor\frac{A}{x}\rfloor\sum_{lcm(d,p)|y}^B\lfloor\frac{B}{y}\rfloor\sum_{lcm(p,q)|z}^C\lfloor\frac{C}{z}\rfloor\\ \text{define } f(n,t)=\sum_{t|x}\lfloor\frac{n}{x}\rfloor ,N=\max(A,B,C)\\ \cdots=\sum_{d=1}^N\mu(d)\sum_{p=1}^N\mu(p)\sum_{q=1}^N\mu(q)f(A,lcm(d,q))f(B,lcm(d,p))f(C,lcm(p,q))\\ \]

计算答案

其中\(f(n,t)\)可以\(O(n\log n)\)预处理。

考虑对\(T\)个点连边建图,\(u\)\(v\)之间有边当且仅当\(\mu(u)\not=0,\mu(v)\not=0,lcm(a,b)\not>T\)。那么图中的每个三元环都能算入答案,这里的三元环还包括只有俩点的和只有单点的。

对于包含三个点的\(<d,p,q>\)的贡献为
\[ \mu(d)\mu(p)\mu(q)\times\\ (f(A,lcm(d,q))f(B,lcm(d,p))f(C,lcm(p,q))+\\ f(A,lcm(d,q))f(B,lcm(p,q))f(C,lcm(d,p))+\\ f(A,lcm(d,p))f(B,lcm(d,q))f(C,lcm(p,q))+\\ f(A,lcm(d,p))f(B,lcm(p,q))f(C,lcm(d,q))+\\ f(A,lcm(p,q))f(B,lcm(d,p))f(C,lcm(d,q))+\\ f(A,lcm(p,q))f(B,lcm(d,q))f(C,lcm(d,p))) \]
对于包含两个、一个的环同理。统计三元环的方法参照不常用的黑科技——「三元环」

参考实现

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;

//[SDOI2018]旧试题

int pr[N],cnt;
int mu[N],bk[N],deg[N];
long long fa[N],fb[N],fc[N]; 
bool vis[N];
struct Node {int u,v,w;};
struct Edge {int ver,len;};

Node ech[N*300];
vector<Edge> e[N];

int solve(int a,int b,int c) {
    long long ans=0;
    int n=max(a,max(b,c)),m=0;
    for(int i=1; i<=n; ++i) {
        deg[i]=fa[i]=fb[i]=fc[i]=0;
        e[i].clear();
    }
    for(int i=1; i<=n; ++i) {
        for(int x=i; x<=n; x+=i) {
            fa[i]+=a/x,fb[i]+=b/x,fc[i]+=c/x;
        }
    }
    for(int i=1; i<=a&&i<=b&&i<=c; ++i) {
        if(mu[i]) ans+=mu[i]*mu[i]*mu[i]*fa[i]*fb[i]*fc[i];
    }
    for(int g=1; g<=n; ++g) {
        for(int i=1; i*g<=n; ++i) if(mu[i*g]) {
            for(int j=i+1; 1LL*i*j*g<=n; ++j) if(mu[j*g]&&__gcd(i,j)==1) {
                int u=i*g,v=j*g,w=i*j*g; 
                deg[u]++,deg[v]++,ech[++m]=(Node){u,v,w};
                ans+=mu[u]*mu[u]*mu[v]*(fa[u]*fb[w]*fc[w]+fa[w]*fb[u]*fc[w]+fa[w]*fb[w]*fc[u]);
                ans+=mu[u]*mu[v]*mu[v]*(fa[v]*fb[w]*fc[w]+fa[w]*fb[v]*fc[w]+fa[w]*fb[w]*fc[v]);
            }
        }
    }
    for(int i=1; i<=m; ++i) {
        if(deg[ech[i].u]<deg[ech[i].v]||(deg[ech[i].u]==deg[ech[i].v]&&ech[i].u<ech[i].v)) 
            swap(ech[i].u,ech[i].v);
        e[ech[i].u].push_back((Edge){ech[i].v,ech[i].w});
    }
#define veit vector<Edge>::iterator 
    for(int i=1; i<=n; ++i) if(mu[i]) {
        for(veit j=e[i].begin(); j!=e[i].end(); ++j) bk[j->ver]=j->len;
        for(veit j=e[i].begin(); j!=e[i].end(); ++j) {
            for(veit k=e[j->ver].begin(); k!=e[j->ver].end(); ++k) {
                if(!bk[k->ver]) continue;
                ans+=mu[i]*mu[j->ver]*mu[k->ver]*(
                    fa[j->len]*fb[k->len]*fc[bk[k->ver]]+fa[j->len]*fb[bk[k->ver]]*fc[k->len]+fa[k->len]*fb[j->len]*fc[bk[k->ver]]+
                    fa[k->len]*fb[bk[k->ver]]*fc[j->len]+fa[bk[k->ver]]*fb[j->len]*fc[k->len]+fa[bk[k->ver]]*fb[k->len]*fc[j->len]
                );
            }
        }
        for(veit j=e[i].begin(); j!=e[i].end(); ++j) bk[j->ver]=0;
    }
    return (ans%mod+mod)%mod;
}

void sieve() {
    mu[1]=1;
    for(int i=2; i<N; ++i) {
        if(!vis[i]) mu[pr[++cnt]=i]=-1;
        for(int j=1; j<=cnt&&i*pr[j]<N; ++j) {
            vis[i*pr[j]]=1;
            if(i%pr[j]==0) break;
            else mu[i*pr[j]]=-mu[i];
        }
    }
}

int main() {
    sieve();
    int T,a,b,c;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&a,&b,&c);
        printf("%d\n",solve(a,b,c)); 
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nosta/p/10544559.html