Codeforces 235E Number Challenge 莫比乌斯反演+数论

题意

设d(s)表示s的约数个数,给出a,b,c,求

i=1aj=1bk=1cd(ijk) ∑ i = 1 a ∑ j = 1 b ∑ k = 1 c d ( i j k )

a,b,c<=2000

分析

题解貌似是一个很鬼畜的做法。。。
约数个数函数 σ0(d) σ 0 ( d ) 有一个小结论,就是

σ0(ij)=p|iq|j[(p,q)=1] σ 0 ( i j ) = ∑ p | i ∑ q | j [ ( p , q ) = 1 ]

这个东西推广到三个数的成绩同样也是成立的,那么我们要求的就是
(i,j)=1,(j,k)=1,(i,k)=1aibjck ∑ ( i , j ) = 1 , ( j , k ) = 1 , ( i , k ) = 1 ⌊ a i ⌋ ⌊ b j ⌋ ⌊ c k ⌋

枚举i和j,式子变成
i=1aj=1b[(i,j)=1]aibjk=1c[(ij,k)=1]ck ∑ i = 1 a ∑ j = 1 b [ ( i , j ) = 1 ] ⌊ a i ⌋ ⌊ b j ⌋ ∑ k = 1 c [ ( i j , k ) = 1 ] ⌊ c k ⌋

不妨设
f(s)=k=1c[(s,k)=1]ck f ( s ) = ∑ k = 1 c [ ( s , k ) = 1 ] ⌊ c k ⌋

我们只要通过反演在 O(n2logn) O ( n 2 l o g n ) 把所有 f(s) f ( s ) 求出来,然后就可以在 O(n2logn) O ( n 2 l o g n ) 的复杂度内求答案了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;

const int N=2005;
const int MOD=1073741824;

int a,b,c,n,tot,prime[N*N],mu[N*N],f[N],s[N*N];
bool not_prime[N*N];

void mod(int &x)
{
    x-=x>=MOD?MOD:0;
}

int gcd(int x,int y)
{
    if (!y) return x;
    else return gcd(y,x%y);
}

void get_prime(int n)
{
    mu[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (!not_prime[i]) prime[++tot]=i,mu[i]=-1;
        for (int j=1;j<=tot&&i*prime[j]<=n;j++)
        {
            not_prime[i*prime[j]]=1;
            if (i%prime[j]==0) break;
            mu[i*prime[j]]=-mu[i];
        }
    }
}

int main()
{
    scanf("%d%d%d",&a,&b,&c);
    get_prime(a*b);
    for (int d=1;d<=c;d++)
    {
        int n=c/d;
        for (int i=1,last;i<=n;i=last+1)
        {
            last=n/(n/i);
            mod(f[d]+=(n/i)*(last-i+1));
        }
    }
    for (int i=1;i<=c;i++)
    {
        if (!mu[i]) continue;
        int w=mu[i]*f[i];
        w+=w<0?MOD:0;
        for (int j=i;j<=a*b;j+=i) mod(s[j]+=w);
    }
    int ans=0;
    for (int i=1;i<=a;i++)
        for (int j=1;j<=b;j++)
            if (gcd(i,j)==1) mod(ans+=(LL)(a/i)*(b/j)*s[i*j]&(MOD-1));
    printf("%d",ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值