1. 程式人生 > >6069 (區間素數篩 + 一個數的所有素因子的個數 + 約數定理 + 數學)

6069 (區間素數篩 + 一個數的所有素因子的個數 + 約數定理 + 數學)

In mathematics, the function d(n)d(n) denotes the number of divisors of positive integer nn

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

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

(i=lrd(ik))mod998244353(∑i=lrd(ik))mod998244353
InputThe first line of the input contains an integer T
(1T15)
T(1≤T≤15)
, denoting the number of test cases. 

In each test case, there are 33 integers l,r,k(1lr1012,rl106,1k107)l,r,k(1≤l≤r≤1012,r−l≤106,1≤k≤107).OutputFor 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

題意:輸入 l r k 求   l<= t<=r,  求   對多有滿足條件的t 的   d(t^k)=t^k的所有 不同因子的個數    的總和

思路:想求d(t^k),先求 d(t),根據約數定理 求不同因子的個數,先把 t 表示為不同素因子的積的形式;


n=p1^c1×p2^c2×p3^c3*…*pm^cm

d(n) = (C1 + 1)*(C2 + 1)*...... (Cm+1) ;表示不同因子的個數;

c1+1 為從中可以選出 1個p1,2個p1...... c1個p1,加 1就是 一個p1也不選,光p1這個素數就 c1+1 種情況,然後和其他選出的素因子結合;有一種情況就是 所有的素因子都不選,那麼這種情況 就是 n個素因子為1 的這種情況;

理解了d(n),那麼d(n^k)就好理解了

寫程式碼應注意;

1,用三目運算子時,一定要加括號,就這道題而言,不加括號就是超時;

2,程式碼中用到了 區間素數篩, 還有最重要的時,a[] 和 sum[] 陣列,sum[i] 存 sum[l+i] 的素因子個數;

a[i] = l + i; 找到 l+i的素因子時,一直除到不能整除 這個素因子位置;

3,當一個數 n,把1~根號n 中的素數 能除的都除盡了,但最終 n 不為1,那麼這麼剩餘的n一定是個大素數;

我說這個大素數有兩種情況 (1) n 本身為 素數  (2) n 把1~ 根號n中的素數除完之後,剩餘的數為素數;

如 n = 14,14 把 1~根號14 中的素數都除盡後,剩下 7,7為素數;

程式碼:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long  
#define Max 1000000+10
#define mod 998244353
bool is_prime[Max];  // 0~Max 之間的素數 
ll prime[Max];  // 存 0~Max 之間的素數; 
ll sum[Max];   //  sum[i]表示 l+i的因子個數; 
ll a[Max];     // a[i] = l+i; 為了素數分解; 
  
ll l,r,k;
ll num;

void Prime()
{
	num = 0;
	ll i,j;
	memset(is_prime,true,sizeof(is_prime));
    is_prime[0] = false;
    is_prime[1] = false;
    for(i = 2;i<Max;i++)     
    {
        if(is_prime[i])
        {
            prime[num++] = i;    // 找出1 ~ 1000000中的素數; 
            for(j = 2;i*j<Max;j++)
                is_prime[i*j] = false;
        }
    }
}
int main()
{
	Prime();
    ll i,j,t;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld%lld",&l,&r,&k);
        for(i = 0;i<=r-l;i++)
        {
            sum[i] = 1;    // 要進行乘法,所以要賦值為1; 
            a[i] = l+i;    //  為了把 a[i] == l+i 進行分解; 
        }
         for(i = 0;i<num;i++)
         {
             ll temp = (l/prime[i]+((l%prime[i])?1:0))*prime[i]; 
             // 三目運算子一定要加括號;,不加括號超時; 
			 //找到[l,r]中第一個能被這個素數整除的數;
             
             for(j = temp; j<=r; j += prime[i])     // 先找到能整除素數prime[i]的數; 
             {
                 ll res = 0;
                 while(a[j-l]%prime[i]==0)  // 把這個數進行素數分解; 
                 {
                     a[j-l] /= prime[i];
                     res++;
                 }
                 sum[j-l] = (sum[j-l]*((res*k+1)%mod))%mod; 
             }
         }
        ll res = 0;
        for(i = 0;i<=r-l;i++)
        {
            if(a[i]!=1) sum[i] = sum[i]*(k+1)%mod;  //分解之後,若不是1,一定是個大素數; 
            
            res = (res+sum[i])%mod; 
        }
        printf("%lld\n",res);
    }
    return 0;
}