【数论】关于因数个数的题

(d(x)) 表示 (x) 的约数个数 , (sigma(x)) 表示x的约数和;
若正整数 (m) 的标准分解式为 (m=p_1^{a_1}p_2^{a_2} ... p_k^{a_k})
(m) 所含因数的个数 (d(m)=(a_1+1)(a_2+1)...(a_k+1))
(m) 所有正因数的和 (sigma(m)=frac{p_1^{a_1}-1}{p_1-1}*frac{p_2^{a_2}-1}{p_2-1}*...*frac{p_k^{a_k}-1}{p_k-1})


poi1,洛谷P1403

(sum_{i=1}^{n} {d(i)})(nleq 10^9);
([1,n]) 里有约数 (i) 的个数是 (lfloor{frac ni} floor) ;
类似 整除分块的做法,复杂度(O(2sqrt n))

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int n;
	ll ans=0;
	scanf("%d",&n);
	for(ll l=1,r;l<n;l=r+1)
	{
		r=n/(n/l);
		ans+=(r-l+1)*(n/l);
	}
	printf("%lld
",ans);
}

poi2,洛谷P2323

(sum_{i=l}^{r} {d(i)})(nleq 10^9);
做法同poi1:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+50;
const int inf=0x3f3f3f3f;
int main()
{
    ll x,y,num1=0,num2=0;
    scanf("%lld%lld",&x,&y);
    x--;
    for(ll i=1,j;i<=x;i=j+1)
    {
        j=x/(x/i);
        num1+=(x/i)*(i+j)*(j-i+1)/2;
    }
    for(ll i=1,j;i<=y;i=j+1)
    {
        j=y/(y/i);
        num2+=(y/i)*(i+j)*(j-i+1)/2;
    }
    printf("%lld
",num2-num1);
}

poi3,洛谷P6060

(sum_{i=1}^{n} {d(i^k)})(1leq{n,k}leq{10^7}) ,同时 (T) 个测试样例, (Tleq10^4);
因为(10^7) 内的数最多有8个不同的因子,所以每个数可以预处理成8项式,再预处理前缀和。

假如要筛出大量数能分解的因数个数(比如这道题),那么线性筛的预处理(O(n+8))
不知道该怎么说,下面代码的预处理(参考题解代码来的)很巧妙,(只可意会不可言传

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const int maxn=1e7+5;
const int N=1e7;

int pri[maxn],pp[maxn][9],temp[maxn],pre[maxn];
inline void init()
{
    pp[1][0]=1;
    for(int i=2;i<=N;i++)
    {
        if(!pri[i])
        {
            pri[++pri[0]]=i;pp[i][0]=pp[i][1]=1;pre[i]=1;temp[i]=1;
        }
        for(int j=1,t;j<=pri[0];j++)
        {
            t=i*pri[j];if(t>N)break;
            pri[t]=1;
            if(i%pri[j])temp[t]=1,pre[t]=i;else temp[t]=temp[i]+1,pre[t]=pre[i];
            for(int k=8;k>=1;k--)pp[t][k]=(pp[pre[t]][k]+pp[pre[t]][k-1]*temp[t])%mod;
            pp[t][0]=pp[pre[t]][0];
            if(i%pri[j]==0)break;
        }
    }
    for(int i=2;i<=N;i++)
        for(int j=0;j<=8;j++)pp[i][j]=(pp[i-1][j]+pp[i][j])%mod;
}
int main()
{
    init();
    int T,n,k;
    scanf("%d",&T);
    while(T--)
    {
        ll ans=0;
        scanf("%d%d",&n,&k);
        for(int i=8;i>=0;i--)
            ans=(ans*k%mod+pp[n][i])%mod;
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/kkkek/p/12297663.html