1. 程式人生 > >HDU6069多校第四場 Counting Divisors

HDU6069多校第四場 Counting Divisors

10 48 2302題意: 對l~r中的每個數的因子個數求和(最後求餘);思路: 對於每一個數而言可以進行分解質因數 num=p1^k1*p2^k2……pn^kn 的形式,而當前這個數的因子和(可以整除這個數的數)就是(k1+1)*(k2+1)……*(kn+1)個。而現在題中求i^k,分解質因子中將k乘入可得(k1*k+1)*(k2*k+1)……(kn*k+1)個。 即現在要求每個數的分解質因數,顯然遍歷l~r會超時,於是我們想到對於用素數去遍歷,對於任意一個數num<10^12 它的質因數只全部小於<num/2(還是超記憶體) 於是我們想到對於一個num他的質因數只有可能有一個大於根號num(這樣記憶體就不會爆了,可以線性打表出1e6以內的素數)。 對每個素數去遍歷l~r,記錄下來,得到因式分解,對於l~r的質數加k+1,合數就按照上面的公式計算出來,全部求和得到結果。
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long  long LL;
const LL MOD=998244353;
const LL MAXN=1e6+1;
int primer[MAXN],cnt;
LL p[MAXN];
LL f[MAXN],num[MAXN];
LL l,r,k;
void isprimer()                 //篩選素數存於p陣列 
{
	memset(primer,0,sizeof(primer));
	cnt=0;
	primer[1]=1;
	for(LL i=2;i<MAXN;i++)
	if(!primer[i])
	{
		p[cnt++]=i;
		for(LL j=i*i;j<MAXN;j+=i)  primer[j]=1;
	}
}
int main()
{
	isprimer();
	 int T;
	 scanf("%d",&T);
	 while(T--)
	 {
	 	scanf("%lld%lld%lld",&l,&r,&k);
	 	LL ans=0;
	 	if(l==1) ans=1,l=2;
	 	LL t=r-l; 
		for(LL i=0;i<=t;i++) f[i]=l+i,num[i]=1;
	//	for(int s=0;s<=t;s++) printf(" %lld ",f[s]);
	//	printf("\n");
		 for(LL i=0;i<cnt&&p[i]*p[i]<=r;i++)
		 {
		 	LL temp=l;
		 	if(temp%p[i]) temp=(temp/p[i]+1)*p[i];
		 	//printf(" %lld %lld\n",temp,p[i]);
		 	for(LL j=temp;j<=r;j+=p[i])
		 	{
		 		LL tim=0;
		 		while(f[j-l]%p[i]==0)
		 		{
		 			tim++;
		 			f[j-l]/=p[i];
				 }
				 num[j-l]=(num[j-l]*(tim*k+1))%MOD;
			 }
		
		  } 
	//	for(int s=0;s<=t;s++) printf(" %lld ",f[s]);
	//	printf("\n");
	     for(LL i=0;i<=t;i++) 
	     if(f[i]==1) ans=(ans+num[i])%MOD;
		 else   ans=(ans+(k+1)*num[i])%MOD; 
	     printf("%lld\n",ans);
		  
	 }
	 return 0;
	
 }