HDU6069多校第四場 Counting Divisors
阿新 • • 發佈:2019-02-09
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; }