hdu 多校联赛 Counting Divisors

Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2331    Accepted Submission(s): 836


Problem Description
In mathematics, the function  d(n)  denotes the number of divisors of positive integer  n .

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

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

(i=lrd(ik))mod998244353

 

Input
The first line of the input contains an integer  T(1T15) , denoting the number of test cases.

In each test case, there are  3  integers  l,r,k(1lr1012,rl106,1k107) .
 

Output
For 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
 

Source
 

Recommend
liuyiding

对数轮没有灵性的我在比赛的时候就把这道题丢给了队友 队友也没做出来 5秒的限时还是超时了 到最后也没想出来怎么优化 结果后来看题解发现要用逆向思维来思考这道题 不是数取找因数 而应该用因数取匹配数 

解法:先去打一个1到1e6的素数表,然后去枚举每个素数在区间内的倍数,可以跳着枚举,计算出每个数对应的因子个数,对于每个数的因子个数就等于枚举的因子个数*k+1累乘起来,注意剩下的大素数的判断
比赛是也是素数打表枚举的 ,鬼知道怎么想的去枚举区间的每个数去求因子,妥妥TLE,也有过正解的想法,想过没想太透彻,感觉这种题值得好好反思警戒自己
先去打一个1到1e6的素数表,然后去枚举每个素数在区间内的倍数,可以跳着枚举,计算出每个数对应的因子个数,对于每个数的因子个数就等于枚举的因子个数*k+1累乘起来,注意剩下的大素数的判断

ac代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;//上限开方之后的值
const int mod=998244353;//题目中的条件模值
bool isprime[N];//用来标记一个数是否为质数
int cnt=0;
long long prime[N];//用来存储筛选出来的质数
void doprime()//打表标记出所有质数
{
    memset(isprime,true,sizeof(isprime));
    isprime[0]=isprime[1]=false;
    for(int i=2;i<=N;i++)
        if(isprime[i])//判断是否为质数
    {
        prime[cnt++]=i;
        for(long long j=i+i;j<=N;j+=i)//质数的倍数一定不是质数
            isprime[j]=false;
    }
}
long long l,r,k;
long long n;
long long f[N];//存储l到n的位置
long long num[N];//存储N的
void work(long long p)//这个函数用来判断p为素因子的个数
{
    for(long long i=l/p*p;i<=r;i+=p)
        if(i>=l)
        {
            if(f[i-l]%p==0)
            {
                int a=0;
                while(f[i-l]%p==0)
                {
                    f[i-l]/=p;
                    a++;//f【i-1】这个数组中素因子为p的个数
                }
                num[i-l]=num[i-l]*((long long)a*k+1)%mod;//扩展到k次
            }
        }
}
int main()
{
    doprime();
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%lld%lld%lld",&l,&r,&k);
            n=r-l;//数据的范围
            long long ans=0;//最后的答案的和
            for(int i=0;i<=n;i++)
            {
                f[i]=i+l;//存储的l到n的数值
                num[i]=1;//每个n^k的质因子的个数先赋值为1 即它本身
            }
            for(int i=0;i<cnt;i++)
            {
                if(prime[i]*prime[i]>r)//一个数的因子的平方肯定不会大于这个数本身 用此来判断结束质数的对比条件
                    break;
                work(prime[i]);
            }
            for(int i=0;i<=n;i++)
            {
                if(f[i]>1)
                   num[i]=num[i]*(k+1)%mod;//处理指数k
                ans=(ans+num[i])%mod;
            }
            printf("%lld\n",ans);
        }
        return 0;
}


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值