P4619 [SDOI2018]旧试题

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4619 [SDOI2018]旧试题相关的知识,希望对你有一定的参考价值。

P4619 [SDOI2018]旧试题

题意:

求个式子:
( ∑ i = 1 A ∑ j = 1 B ∑ k = 1 C d ( i ∗ j ∗ k ) ) m o d ( 1 0 9 + 7 ) (\\sum_{i=1}^{A}\\sum_{j=1}^{B}\\sum_{k=1}^{C}d(i*j*k))mod(10^9+7) (i=1Aj=1Bk=1Cd(ijk))mod(109+7)

题解:

原创博文1k纪念


很明显,莫比乌斯反演
马上更新




三元环链接
此等好题,作为第1000题的纪念

代码:

这个题让我写,我是真写不出来,非常适合练练莫比乌斯推导
代码条例非常清晰,很适合阅读

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N= 1e5 + 7;
const int M= 1e6 + 7;
const int mod= 1e9 + 7;
bool Prime[N];
int tot, P[N >> 3], mu[N];
void get_mu()
{
    mu[1]= 1;
    for (int i= 2; i <= 1e5; i++) {
        if (!Prime[i])
            P[++tot]= i, mu[i]= -1;
        for (int j= 1; P[j] * i <= 1e5 && j <= tot; j++) {
            Prime[P[j] * i]= 1;
            if (i % P[j] == 0) {
                mu[P[j] * i]= 0;
                break;
            }
            mu[P[j] * i]= -mu[i];
        }
    }
}
vector<int> ve[N];
unordered_map<int, bool> mp[N];
int T, Max, A, B, C, ans, p[N];
int sA[M], sB[M], sC[M], cnt, deg[N];
int gcd(int x, int y)
{
    return x == 0 ? y : gcd(y % x, x);
}
ll lcm(int x, int y)
{
    return 1ll * x / gcd(x, y) * y;
}
int ta, tb, tc, sum;
void cal(int a, int b, int c)//求后半程三个累加的答案 
{
    sum=(sum+ 1ll * p[a / ta] * p[b / tb] % mod * p[c / tc] % mod)% mod;
}
void get(int a, int b, int c)
{
    sum= 0;
    if (a == b && b == c)
        cal(A, B, C);
    else if (a == b || b == c || c == a) {
        cal(A, B, C);
        cal(C, A, B);
        cal(B, C, A);
    }

    else {//三个点的值都不一样,完全排列 
        cal(A, B, C);
        cal(A, C, B);
        cal(B, A, C);
        cal(B, C, A);
        cal(C, A, B);
        cal(C, B, A);
    }//记录后半程的答案 

    ans= (ans + (mu[a] * mu[b] * mu[c] * sum % mod + mod) % mod) % mod;//记录前半程答案 
}
int vis[N];
void solve()
{
    for (int i= 1; i <= cnt; i++) { 
        int &u= sA[i], &v= sB[i];
        if (deg[u] < deg[v])
            swap(u, v);
        else if (deg[u] == deg[v] && u > v)
            swap(u, v);
        ve[u].push_back(i);//存的点的编号,为了方便后面取值 
    }
    for (int i= 1; i <= Max; i++) {//跑三元环 
        for (int j : ve[i])
            vis[sB[j]]= sC[j];

        for (int j : ve[i])
            for (int k : ve[sB[j]])
                if (vis[sB[k]]) {
                    ta= vis[sB[k]];//分别是三个lcm 
                    tb= sC[j];
                    tc= sC[k];
                    get(i, sB[j], sB[k]);//三个点的值 
                }

        for (int j : ve[i])
            vis[sB[j]]= 0;
    }
}
void getans(int x)
{
    for (int l= 1, r; l <= x; l= r + 1) {
        r= (x / (x / l));
        p[x]= (p[x] + 1ll * (r - l + 1) * (x / l) % mod) % mod;
		//整除分块前缀和 
    }
}
int main()
{
    scanf("%d", &T);
    get_mu();
    for (int i= 1; i <= 1e5; i++)
        getans(i);
    while (T--) {
        scanf("%d%d%d", &A, &B, &C);
        ans= cnt= 0;
        Max= max(max(A, B), C);
        for (int i= Max; i >= 1; i--) {//i枚举的是三数的人最大公约数
            for (int j= i; j <= Max; j+= i) {
                if (!mu[j])
                    continue;
                for (int k= j; 1ll*k*j /i<= 1ll * Max; k+= i) {//k*j/i就是这个两个数的lcm,要小于等于Max 
                    if (!mu[k])
                        continue;
                    if (!mp[j][k]) {
//                        printf("%d %d %d i=%d\\n", j, k, j / i * k,i);
                        ++cnt;
                        sA[cnt]= j;
                        sB[cnt]= k;
                        sC[cnt]= 1ll*j*k/ i  ;//sC是j和k的最小公倍数 
                        deg[j]++;
						deg[k]++;
                        mp[j][k]= 1;
                    }
                }
            }
        }

        solve();
        for (int i= 1; i <= Max; i++) {
            ve[i].clear();
            mp[i].clear();
            deg[i]= 0;
        }

        printf("%d\\n", (ans + mod) % mod);
    }
    return 0;
}

以上是关于P4619 [SDOI2018]旧试题的主要内容,如果未能解决你的问题,请参考以下文章

P4619 [SDOI2018]旧试题(莫比乌斯反演,建图优化三重枚举,三元环计数,神仙好题,超级清晰易懂)

[bzoj 5332][SDOI2018]旧试题

Bzoj5332: [Sdoi2018]旧试题

片段(Java) | 机试题+算法思路+考点+代码解析 2023

JavaScript笔试题(js高级代码片段)

「SDOI2018」物理实验