2017 Multi-University Training Contest 4 1003 || HDU6069

哆啦A梦传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6069

题目大意:

给出l,r,k,计算l到r每个数的k次方的因子个数的和

官方题解:

设n= pc11pc22pckk ,则 dnk=(kc1+1)(kc2+1)(kcm+1) ,枚举不超过 r 的所有质数p,再枚举区间[l,r]中所有p的倍数,将其分解质因数,最后剩下的部分就是超过 r 的质数,只可能是0个或1个。

大意是枚举质数对区间筛

代码:

    #include <iostream>
#include <bits/stdc++.h>
#define MOD 998244353
#define MAXN 1000005
typedef long long ll;
using namespace std;

int prime[MAXN];
bool is_prime[MAXN];
int sieve(ll n)                                 /**筛法打表,用线筛时间上也差不多**/
{                                               /**筛1e6就足够了,因为r最大就1e12**/
    ll p=0;
    for(ll i=0;i<=n;i++)
    {
        is_prime[i]=true;
    }
    is_prime[0]=is_prime[1]=false;
    for(ll i=2;i<=n;i++)
    {
        if(is_prime[i])
        {
            prime[p++]=i;
            for(ll j=2*i;j<=n;j+=i)
                is_prime[j]=false;
        }
    }
    return p;
}
ll a[MAXN];               /**a数组记录数字,b数组记录(kc1+1)(kc2+1)……(kck+1)的乘积**/
ll b[MAXN];
int main()
{
    int t;
    scanf("%d",&t);
    int v=sieve(1000001);
    while(t--)
    {
        ll l,r,k,sum=0;
        scanf("%lld%lld%lld",&l,&r,&k);
        for(ll i=l;i<=r;i++)
        {
            a[i-l]=i;
            b[i-l]=1;
        }
        for(ll i=0;prime[i]*prime[i]<=r&&i<v;i++)
        {
            ll x=l-l%prime[i];
            while(x<l) x+=prime[i];
            for(ll j=x;j<=r;j+=prime[i])
            {
                int cnt=0;
                while(a[j-l]%prime[i]==0)
                {
                    cnt++;
                    a[j-l]/=prime[i];
                }
                b[j-l]=(b[j-l]*(k*cnt+1))%MOD;
            }
        }
        for(ll i=l;i<=r;i++)
        {
            if(a[i-l]!=1) b[i-l]=b[i-l]*(k+1)%MOD;         /**a[i-l]!=1意味着筛不走的质数**/
        }
        for(ll i=l;i<=r;i++)
        {
            sum+=b[i-l]%MOD;
        }
        printf("%lld\n",sum%MOD);
    }
    return 0;
}

附上标程:

#include<cstdio>
typedef long long ll;
const int N=1000010,P=998244353;
int Case,i,j,k,p[N/10],tot,g[N],ans;ll n,l,r,f[N];bool v[N];
inline void work(ll p){
  for(ll i=l/p*p;i<=r;i+=p)if(i>=l){
    int o=0;
    while(f[i-l]%p==0)f[i-l]/=p,o++;
    g[i-l]=1LL*g[i-l]*(o*k+1)%P;
  }
}
int main(){
  for(i=2;i<N;i++){
    if(!v[i])p[tot++]=i;
    for(j=0;j<tot&&i*p[j]<N;j++){
      v[i*p[j]]=1;
      if(i%p[j]==0)break;
    }
  }
  scanf("%d",&Case);
  while(Case--){
    scanf("%lld%lld%d",&l,&r,&k);
    n=r-l;
    for(i=0;i<=n;i++)f[i]=i+l,g[i]=1;
    for(i=0;i<tot;i++){
      if(1LL*p[i]*p[i]>r)break;
      work(p[i]);
    }
    for(ans=i=0;i<=n;i++){
      if(f[i]>1)g[i]=1LL*g[i]*(k+1)%P;
      ans=(ans+g[i])%P;
    }
    printf("%d\n",ans);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值