HDU 2017 多校联合训练赛4 4003 6069 Counting Divisors 素数筛和素因数分解

Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)


Problem Description
In mathematics, the function d(n) denotes the number of divisors of positive integer n.

For example, d(12)=6 because 1,2,3,4,6,12 are all 12's divisors.

In this problem, given l,r and k, your task is to calculate the following thing :

(i=lrd(ik))mod998244353

 

Input
The first line of the input contains an integer T(1T15), denoting the number of test cases.

In each test case, there are 3 integers l,r,k(1lr1012,rl106,1k107).
 

Output
For each test case, print a single line containing an integer, denoting the answer.
 

Sample Input
 
   
3 1 5 1 1 10 2 1 100 3
 

Sample Output
 
   
10 48 2302
 

Source
2017 Multi-University Training Contest - Team 4


题目大意
已知l,r,k,i为区间 [ l , r ] 中的任意整数,求所有 i^k 的因子个数的和。


题目分析
首先我们要知道两条性质:
1.对于 每个大于1的 自然数, 都可以分解为质数的 积的形式 ,并且这种形式是唯一的 。举个栗子:6936 = 2^3*3*17^2。

2.这个数n的约数的个数是:(接上一个栗子:f(6936) = (3+1)*(1+1)*(2+1) = 24)

其中,p1、p2、p3,…pk为互异质数,其中a1、a2、a3…ak是p1、p2、p3,…pk的指数。

另外,对于一个数i^k,它的约数个数是(a1*k+1)(a2*k+1)……(ai*k+1)。

这样,问题就转化成,对一个数i的质因数分解,一开始的思路是首先筛出小于10^6所有素数,然后进行质因数分解,结果超时了。赛后看题解,标程的做法是,设置了两个数组f[ ](存区间[ l , r ]的所有数),g[ ](存对应f[ ]的约数个数的计算结果),枚举小于10^6的所有质数,针对枚举的质数p,分解所有p的倍数的以p作为质因子的项,(注意,数组f[ ]和g[ ]存的都是分解到当前质因子p的结果,详情请参考代码函数work( ))。
标程的方法快在,只需要遍历一边质数集合就将区间中的所有数都分解好了,而不是区间中的每个数都分别进行因数分解。

最后,需要提醒一下,对于一个数i的质因数分解,最终剩下的部分可能是1或者是一个大于sqrt(i)的质数,所以,在最后,如果f[i]>1,我们需要将这个质因子加到最终结果中。


另附官方题解

n=p1c1p2c2...pmcm,则d(nk)=(kc1+1)(kc2+1)...(kcm+1)

枚举不超过r\sqrt{r}的所有质数pp,再枚举区间[l,r][l,r]中所有pp的倍数,将其分解质因数,最后剩下的部分就是超过r\sqrt{r}的质数,只可能是00个或1个。

时间复杂度O(r+(r−l+1)loglog(r−l+1))O(\sqrt{r}+(r-l+1)\log\log(r-l+1))



代码
#include 
#include 
using namespace std;
typedef long long ll;
const int N = 1000010;
const int mod = 998244353;
int cas, k;
ll l, r, n;//n为区间长度
ll f[N];//记录区间l~r之间的所有数,并且用于素数分解操作
int g[N];//记录f[]中所对应的数的分解素数的(指数*k+1)的累乘积
int tot;//总质数的个数
int prime[N/10];//记录所有的质数
bool vis[N];//1为合数,0为质数
int i, j;
ll ans;
int cnt;

void isprime()
{
    tot = 0;
    //memset(vis, 0, sizeof(vis));
    for (i=2; i=l)
        {
            cnt = 0;//p的指数
            while (f[i-l] && f[i-l]%p == 0)
            {
                f[i-l] /= p;
                cnt ++;
            }
            g[i-l] = 1LL*g[i-l]*(cnt*k+1)%mod;
        }
    }
}

int main()
{
    isprime();
    //for (i=0; i r)
                break;
            work(prime[i]);

        }
        ans = 0;
        for (i=0; i<=n; i++)
        {
            if(f[i] > 1)
                g[i] = 1LL*g[i]*(1*k+1)%mod;
            ans = (ans+g[i])%mod;
        }
        printf ("%lld\n",ans);
    }
    return 0;
}



你可能感兴趣的:(HDU,2017,多校联合赛1)