HDU 6069 Counting Divisors

来源:互联网 发布:天猫美工岗位职责 编辑:程序博客网 时间:2024/05/18 07:16

【题目链接】http://acm.hdu.edu.cn/showproblem.php?pid=6069

题目意思

给你了l,r,k。问你i从l到r,i^k因子个数的总和

解题思路

根据约数个数定理:n=p1^a1×p2^a2×p3^a3*…*pk^ak,n的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1).(p为质数)
若i=p1^a1×p2^a2×p3^a3*…*pk^ak,则i^K=p1^(a1*K)×p2^(a2*K)×p3^(a3*K)*…*pk^(ak*K),i^K的约数的个数就是(a1*K+1)(a2*K+1)(a3*K+1)…(ak*K+1),由此可推出质数的因子数为k+1。质数的a次方就有(a*k)+1个因子
这样只要把区间里的合数分为质数乘积就可以了。(如:12=2*2*3,他的因子数就为(2*1+1)*(1+1)=6

代码部分

///发现写的是没大佬的好把大佬的代码借用了#include<bits/stdc++.h>typedef long long ll;using namespace std;const int maxn=1e6+10;const int mod=998244353;int tot,t;ll l,r,k,ans,cnt[maxn],q[maxn],pri[maxn];bool vis[maxn];void init()   ///筛选法质数打表{    for(int i=2; i<maxn; i++)    {        if(!vis[i])            pri[tot++]=i;        for(int j=0; j<tot; j++)        {            int k=i*pri[j];            if(k>maxn)break;            vis[k]=1;        }    }}int main(){    scanf("%d",&t);    init();    while(t--)    {        scanf("%lld%lld%lld",&l,&r,&k);        ans=0;        if(l==1) ans++,l++;        for (ll i=0; i<=r-l; i++)        {            cnt[i]=1;   ///存对应的l+i里有多少个质数            q[i]=l+i;   ///存下标        }        for (ll i=0; pri[i]*pri[i]<=r; i++)         {            ll j=l/pri[i]+(l%pri[i]!=0);   ///找到这个质数第一个出现的给定区间的倍数            for (j=j*pri[i]; j<=r; j+=pri[i])  ///从区间里第一个质数倍数到最后一个            {                ll tmp=0;                  while (q[j-l]%pri[i]==0)                {                    q[j-l]/=pri[i];  ///求可以分解多少个pre[i],                     tmp++;                }                cnt[j-l]*=(tmp*k)%mod+1;   ///tmp个pir[i]所以cnt[j-1]有(tmp*k)%mod+1个质数                cnt[j-l]%=mod;             }        }        for (ll i=0; i<=r-l; i++)        {            if (q[i]!=1)   ///可能残留大于根号r的一个质数                ans+=((k+1)*cnt[i])%mod;            else ans+=cnt[i];            ans%=mod;        }        printf("%lld\n",ans);    }}
原创粉丝点击