HDU5528 积性函数

本文解析了HDU5528题目,介绍了如何计算选择两个非负整数a和b使得a×b mod m ≠ 0的方法,并通过函数f(m)和g(n)进行了详细阐述。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU 5528

Marry likes to count the number of ways to choose two non-negative integers aa and bbless than mm to make a×ba×b mod m≠0m≠0.

Let’s denote f(m)f(m) as the number of ways to choose two non-negative integers aa and bbless than mm to make a×ba×b mod m≠0m≠0.

She has calculated a lot of f(m)f(m) for different mm, and now she is interested in another function g(n)=∑m|nf(m)g(n)=∑m|nf(m). For example, g(6)=f(1)+f(2)+f(3)+f(6)=0+1+4+21=26g(6)=f(1)+f(2)+f(3)+f(6)=0+1+4+21=26. She needs you to double check the answer.

img

Give you nn. Your task is to find g(n)g(n) modulo 264264.

Input

The first line contains an integer TT indicating the total number of test cases. Each test case is a line with a positive integer nn.

1≤T≤200001≤T≤20000
1≤n≤1091≤n≤109

Output

For each test case, print one integer ss, representing g(n)g(n) modulo 264264.

Sample Input

2
6
514

Sample Output

26
328194

思路

我们考虑f(n)f(n)怎么计算 ,f(n)f(n)等于n2n2减去是nn的倍数的方案数

h(n)表示是nn的倍数的方案数,则h(n)=d|nφ(nd)d 如何理解呢?我们去枚举gcd(a,N)gcd(a,N)的值,可知这个值会等于NN的某个因子,因此我们枚举n的因子,则当gcd(a,N)=dgcd(a,N)=d时,即gcd(ad,Nd)=1gcd(ad,Nd)=1aaφ(Nd)种取值,由于a只有NN的因子d,则b要包含N/dN/d这个因子,那么有多少bb满足呢?即N/N/d=d个 。因此h(n)=d|nφ(nd)dh(n)=∑d|nφ(nd)∗d

所以所求为g(n)=d|nf(d)=d|nd2d|nh(d)g(n)=∑d|nf(d)=∑d|nd2−∑d|nh(d)

对于第二项,质因子分解后,则d|pkh(d)=d|pkd|dφ(dd)d∑d|pkh(d)=∑d|pk∑d′|dφ(dd′)d′

对于pkpk的因子只有k+1k+1个,即loglog级别,因此总共只有质因子分解的时间

总时间复杂度O(T(nlog(n)+log2n))O(T∗(nlog(n)+log2n)) 注意这里质因子分解时用素数去筛(先预处理出素数) 否则TLETLE

本题还有一种思路 我们知道d|nφ(d)=n∑d|nφ(d)=n,其卷积形式为φI=Iφ=idφ∗I=I∗φ=id 其中II为恒等1函数,id为单位函数。本题我们要求解的是d|nh(n)=d|nw|dφ(dw)w=d|n(φid)(d)=Iφid=(Iφ)id=idid=d|nid(d)id(nd)=d|ndnd=d|nn=nd|n1=n(n)∑d|nh(n)=∑d|n∑w|dφ(dw)⋅w=∑d|n(φ∗id)(d)=I∗φ∗id=(I∗φ)∗id=id∗id=∑d|nid(d)⋅id(nd)=∑d|nd⋅nd=∑d|nn=n⋅∑d|n1=n乘以(n的因子数目)

几个式子总结:

  • d|nφ(d)=n∑d|nφ(d)=n
  • d|nφ(nd)d=gcd(i,n)(1<=i<=n)=∑d|nφ(nd)∗d=∑gcd(i,n)(1<=i<=n)=[0,n)[0,n)中任选两个数a,ba,b,且aba∗bnn的倍数的方案数
  • d|nw|dφ(dw)w=n(n)

代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;

bool valid[35000];
int ans[35000];
int tot=0;

void get_prime(int n)
{
    tot=0;
    memset(valid,true,sizeof(valid));
    for(int i=2;i<=n;++i){
        if(valid[i]){
            ans[++tot]=i;
        }
        for(int j=1;j<=tot&&ans[j]*i<=n;++j){
            valid[ans[j]*i]=false;
            if(i%ans[j]==0) break;
        }
    }
}

int main()
{
    //cout<<(1<<30)<<endl;
    int t;
    get_prime(35000);
    //cout<<tot<<endl;
    //cin>>t;
    scanf("%d",&t);
    while(t--)
    {
        //assert(t>15000);
        ll n;
        scanf("%lld",&n);
        ll ans1=1;
        ll ans2=1;
        for(int i=1;ans[i]*ans[i]<=n;++i){
            ll p[35];
            if(n%ans[i]==0){
                ll res=0;
                ll res1=0;
                res1+=1*1;
                int k=0;p[0]=1;
                while(n%ans[i]==0){
                    n/=ans[i];
                    k++;
                    p[k]=p[k-1]*ans[i];
                    res1+=(p[k]*p[k]);
                }
                //cout<<k<<endl;
                ans1*=res1;
                //assert(ans1<(1LL<<62));
                for(int j=0;j<=k;++j){
                    for(int d=0;d<=j;++d){
                        if(j>d) res+=(p[j-d]-p[j-d-1])*p[d];
                        else res+=p[d];
                    }
                }
                ans2*=res;
            }
        }
        if(n>1){
            ans1*=(1+n*n);
            ll res=0;
            res+=n+n;
            ans2*=res;
        }
        //ans2=0;
        printf("%lld\n",ans1-ans2);
        //cout<<ans1-ans2<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值