设 (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);
}
}