【2018 Multi-University Training Contest 10】Calculate(莫比乌斯反演)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coldfresh/article/details/82024079

Problem Description
Given A, B, C, Calculate
这里写图片描述

Where φ(n) denotes the number of positive integers ≤ n that are relatively prime to n.

Input
The first line of the input contains an integer T , denoting the number of test cases. In each test case, there are three integers A, B, C in one line, as described above.
1 ≤ T ≤ 10, 0 < A, B, C ≤ 10^7

Output
For each test case, output one line contains a single integer, denoting the answer modulo 2^30.

Sample Input
4
96 93 95
970 906 893
92460 95043 54245
9760979 8053227 7156842

Sample Output
1114536
28070648
388873924
623507672

为方便起见下文 ( a , b ) 均指代 g c d ( a , b )
题解给的东西跳过太多步骤了,我觉正常思路应该是这样的:

i = 1 A j = 1 B k = 1 C ϕ ( ( i , j 2 , k 3 ) ) = i = 1 A j = 1 B k = 1 C d | i , d | j 2 , d | k 3 ϕ ( d ) [ ( i d , j 2 d , k 3 d ) == 1 ]

易知有:
g ( n ) = d | n μ ( d ) = [ n == 1 ? 1 : 0 ]

所以有:
= i = 1 A j = 1 B k = 1 C d | i , d | j 2 , d | k 3 ϕ ( d ) l | ( i d , j 2 d , k 3 d ) μ ( l ) = i = 1 A j = 1 B k = 1 C d | i , d | j 2 , d | k 3 ϕ ( d ) l | i d , l | j 2 d , l | k 3 d μ ( l )

那么到这里,我们去枚举 t = l d ,显然我们可以发现t是同样满足 t | i , t | j 2 , t | k 3 .那么里面的l和d就是一个狄利克雷卷积的形式了
得:
i = 1 A j = 1 B k = 1 C t | i , t | j 2 , t | k 3 ( μ ϕ ) ( t )

这里才到题解的第一步……..
后面就是反演的套路啊,把里面的东西拿到外面来:
t = 1 ( μ ϕ ) ( t ) t | i A t | j 2 B t | k 3 C

至于后面这个东西,也的确是厉害,但是只要用唯一分解定理简单分析一下,其实就是可以了
A的个数显然是 A t
那第二个呢?实际上j平方代表了本来我的因子不够,但是平方了以后就足够整除t了,所以答案一定变大的,本质原因就是对于 k 次:

f k ( x ) = i = 0 p i a i k

显然k等于1时, f 1 ( x ) = x ,那么B就是 B f 2 ( t ) ,C的贡献就是 C f 3 ( t )
狄利克雷卷积是积性, f k 显然也是积性均可以线性筛。
就可以做了。。。。。。
具体实现,需要记录一下每个数最小质因子的幂次,来得到 f k

这题如果不用unsigned int就会超时啊。。。
代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ull  unsigned long long
#define ll long long
#define ul unsigned int
#define maxn 10000005
using namespace std;
ul mod=1<<30;
bool isP[maxn];
int prime[maxn],cnt=0;
int g[maxn];
int e[maxn];//数中最小质数的幂次大小
int p[maxn];
int f2[maxn],f3[maxn];
void init()
{
    g[1]=f2[1]=f3[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!isP[i])
        {
            prime[cnt++]=i;
            g[i]=i-2;
            e[i]=1;
            p[i]=f2[i]=f3[i]=i;
        }
        for(int j=0;j<cnt&&(ll)i*prime[j]<maxn;j++)
        {
            int _p=prime[j];
            int now=i*_p;
            isP[now]=true;
            if(i%_p)
            {
                e[now]=1;
                p[now]=_p;
                f2[now]=f2[i]*_p;
                f3[now]=f3[i]*_p;
                g[now]=g[i]*(_p-2);
            }
            else
            {
                e[now]=e[i]+1;
                p[now]=p[i]*_p;
                f2[now]=f2[i]*(e[i]%2?1:_p);
                f3[now]=f3[i]*(e[i]%3?1:_p);
                g[now]=(p[now]-p[now]/_p*2+p[now]/(_p*_p))*g[now/p[now]];
                break;
            }
        }
    }
}
int A,B,C;
int main()
{
    init();
    int t;
    cin>>t;
    while(t--)
    {
        cin>>A>>B>>C;
        ul ans=0;
        for(int i=1;i<=A;i++)
           ans+=g[i]*(A/i)*(B/f2[i])*(C/f3[i]);

        cout<<(ans&(mod-1))<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Coldfresh/article/details/82024079