hdu6069 区间素数筛

hdu6069 Counting Divisors
传送门
题意
计算\((\sum_{i=l}^{r}d(i^k))\ mod\ 998244353\),其中\(d(n)\)表示\(n\)的约数个数,其中\(1\leq l\leq r\leq 1e12,r-l\leq 1e6,1\leq k\leq 1e7\)
题解
根据唯一分解定理
\(n=p_1^{c_1}*p_2^{c_2}*p_3^{c_3}*...*p_m^{c_m}\)
所以
\(d(n)=(c_1+1)*(c_2+1)*(c_3+1)*...*(c_m+1)\)
所以
\(d(n^k)=(kc_1+1)*(kc_2+1)*(kc_3+1)*...*(kc_m+1)\)
所以就是对\([l,r]\)区间中的每一个数进行质因数分解,可以通过区间素数筛计算每一个素数的贡献

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<climits>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PLI pair<LL,int>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;

const int maxn=1e6+10,mod=998244353;
int T;
bool is_prime[maxn];
LL l,r,k,ans[maxn],cur[maxn];

void segment_sieve(LL a,LL b){
	int t=sqrt(b);
	for(int i=2;i<=t;i++) is_prime[i]=1;
	for(int i=0;i<=b-a;i++) cur[i]=i+a;
	for(int i=2;i<=t;i++){
		if(is_prime[i]){
			for(int j=2*i;j<=t;j+=i){
				is_prime[j]=0;
			}
			for(LL j=(a+i-1)/i*i;j<=b;j+=i){
				LL cnt=0;
				while(cur[j-a]%i==0){
					cnt++;
					cur[j-a]/=i;
				}
				cnt=cnt*k%mod;
				ans[j-a]=ans[j-a]*(cnt+1)%mod;
			}
		}
	}
	for(int i=0;i<=b-a;i++){
		if(cur[i]!=1){
			ans[i]=ans[i]*(k+1)%mod;
		}
	}
}

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%lld %lld %lld",&l,&r,&k);
		LL n=r-l+1;
		for(int i=0;i<n;i++) ans[i]=1;
		segment_sieve(l,r);
		LL res=0;
		for(int i=0;i<n;i++){
			res=(res+ans[i])%mod;
		}
		printf("%lld\n",res);
	}
}
posted @ 2020-09-23 16:05  fxq1304  阅读(98)  评论(0编辑  收藏  举报