SPOJ 34096 Counting Divisors (general) 发表于 2019.07.28 | 分类于 题解 | 20 考虑函数 f(x)=σ0(xk) 在质数和质数次幂处的值。 考虑 f(p),容易发现 f(p)=σ0(pk)=k+1。 考虑 f(pc),容易发现 f(pc)=σ0((pc)k)=σ0(pck)=ck+1。 其中 p 为任意质数。 于是直接套用模板即可。 代码: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465#include <cstdio>#include <cstring>#include <cmath>using namespace std;const long long N = 1e10;const int MX = 1e5;int T;unsigned long long n,K;int lim;int vis[MX + 5],cnt,prime[MX + 5];int tot,le[MX + 5],ge[MX + 5];inline int &id(long long x){ return x <= lim ? le[x] : ge[n / x];}unsigned long long lis[2 * MX + 5];unsigned long long G[2 * MX + 5],Fprime[2 * MX + 5];unsigned long long F(int k,unsigned long long n){ if(n < (unsigned long long)prime[k] || n <= 1) return 0; unsigned long long ret = Fprime[id(n)] - (k - 1) * (K + 1); for(register int i = k;i <= cnt && (unsigned long long)prime[i] * prime[i] <= n;++i) { unsigned long long pw = prime[i],pw2 = (unsigned long long)prime[i] * prime[i]; for(register int c = 1;pw2 <= n;++c,pw = pw2,pw2 *= prime[i]) ret += (c * K + 1) * F(i + 1,n / pw) + ((c + 1) * K + 1); } return ret;}int main(){ for(register int i = 2;i <= MX;++i) { if(!vis[i]) prime[++cnt] = i; for(register int j = 1;j <= cnt && i * prime[j] <= MX;++j) { vis[i * prime[j]] = 1; if(!(i % prime[j])) break; } } scanf("%d",&T); for(;T;--T) { scanf("%llu%llu",&n,&K),lim = sqrt(n),tot = 0; for(unsigned long long l = 1,r;l <= n;l = r + 1) { r = n / (n / l); lis[id(n / l) = ++tot] = n / l; G[tot] = n / l - 1; } for(register int k = 1;k <= cnt;++k) { int p = prime[k]; unsigned long long s = (unsigned long long)p * p; for(register int i = 1;lis[i] >= s && i <= tot;++i) G[i] -= G[id(lis[i] / p)] - (k - 1); } for(register int i = 1;i <= tot;++i) Fprime[i] = (K + 1) * G[i]; printf("%llu\n",F(1,n) + 1); }} 本文作者: Alpha1022 本文链接: https://www.alpha1022.me/articles/spoj-34096.htm 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!