HDU 6069 Counting Divisors【素数筛法】

来源:互联网 发布:现在开童装淘宝店 编辑:程序博客网 时间:2024/05/16 16:03

题目链接

题意:求l到r中所有数的k次方的因数个数之和。

将i分解质因数,则d(i)等于各个质因数上的指数+1之积。因此d(i^k)等于(i*k+1)之积。l,r<=1e12,因此筛出1e6以内的素数,然后枚举每个素数,再枚举这个素数的每个倍数,将其分解质因数。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define ll long longconst int maxn = 1e6 + 10;const ll MOD = 998244353;bool isprime[maxn];ll prime[maxn];int cnt = 0;void getprime() // 筛出1e6以内的素数{    memset(isprime, true, sizeof(isprime));    isprime[0] = isprime[1] = false;    for (ll i = 2; i <= 1000000; i++)    {        if (isprime[i])        {            prime[++cnt] = i;            for (ll j = i * i; j <= 1000000; j += i)                isprime[j] = false;        }    }}ll d[maxn];ll arr[maxn];ll solve(ll l, ll r, ll k){    for (int i = 1; i <= cnt; i++) // 枚举每个素数    {        ll tmp = (l + prime[i] - 1) / prime[i] * prime[i];        while (tmp <= r)        {            ll cnt = 0;            while (arr[tmp - l] % prime[i] == 0)            {                cnt++;                arr[tmp - l] /= prime[i];            }            d[tmp - l] *= (k * cnt + 1);            d[tmp - l] %= MOD;            tmp += prime[i]; // 枚举这个素数的所有倍数        }    }    ll ans = 0;    for (ll i = l; i <= r; i++)    {        if (arr[i - l] == 1)    ans += d[i - l];        else    ans += d[i - l] * (k + 1);        ans %= MOD;    }    return ans;}int main(){    getprime();    int T;    scanf("%d", &T);    while (T--)    {        ll l, r, k;        scanf("%lld %lld %lld", &l, &r, &k);        for (ll i = l; i <= r; i++)        {            arr[i - l] = i;            d[i - l] = 1;        }        ll ans = solve(l, r, k);        printf("%lld\n", ans);    }}


原创粉丝点击