• 2017 Multi-University Training Contest


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

    题目意思:首先解释一下d[n]这个函数表示n有多少个因子,百度一下可以知道这个函数是一个非完全积性函数,d[n]=d[i]*d[j]当且仅当i*j=n,且i和j互质,现在求一个[l,r]区间的所有数d[i^k]的和。

    思路:比赛场上知道xjb推出了题目给的这个公式d(n​^k​​)=(kc1​​+1)(kc2​​+1)...(kcm​​+1),还是很容易推了的,可能百度也可以找到吧,还是自己推一下比较好。这里说一下是怎么退出来了。首先对于一个数n可以质因分解出n=p1^m1*p2^m2*p3^m3……ps^ms,其中p1,p2,p3…………ps是互不相同的质数,所以每一项都是互质的。

    所以d[n]=d[p1^m1]*d[p2^m2]*d[p3^m3]……d[ps^ms]。又因为n^k=[p1^m1*p2^m2*p3^m3……ps^ms]*[p1^m1*p2^m2*p3^m3……ps^ms]…………*[p1^m1*p2^m2*p3^m3……ps^ms],k项相乘,合并一下可以得到n^k=p1^(m1*k)*p2^(m2*k)*p3^(m3*k)…………ps^(ms*k),我们知道对于一个素数有两个因数,而p^k(p为素数)的因子数为k+1,我们可以这样反推这个结论。因为一个数有唯一的质因分解,所以p^k的必然分解成k个p,那么所有的p^t(0<=t<=k)必定都是p^k的因数,而p^k的因数不会再有其他数了,所以一共k+1个因子。

    由以上我们证明了d(n​^k​​)=(kc1​​+1)(kc2​​+1)...(kcm​​+1)这个式子,我们现在关键就是把这个式子中的每一个数的每一个c1……cm算出来即可。很明显质因分解计算每个质因子的个数。但是这里用简单的计算不行,所以这道题需要用到区间素数筛,用sqrt(r)内的素数把[l,r]的素数筛出来,那些被筛掉的数必然是被自己的质因子筛掉的。还有一点一个数n的质因子最多只有一个在sqrt(n)的右侧。所以我们建立一个orz数组初始化orz[i-l]=l,然后每次计算一个质因子对他的贡献,就他这些质因子除掉。最后对于那些orz[i-l]!=1的只有两种情况要么是素数,要么是有一个质因子在sqrt(i-l)的右侧,我们只需要再把ans[i-l]*=k+1就好了。

    筛素数的时候多筛点,我因为筛少了,导致wa了5发

    代码:

     1 //Author: xiaowuga
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define mem(s,ch) memset(s,ch,sizeof(s))
     6 const long long N=1e6+20;
     7 const long long mod=998244353;
     8 using namespace std;
     9 typedef long long LL;
    10 bool is_p_small[N];
    11 bool is_p[N];
    12 LL ans[N];
    13 LL l,r,k;
    14 LL orz[N];
    15 LL prime[N];
    16 LL p=0;
    17 void sieve(){
    18     mem(is_p_small,true);
    19     is_p_small[0]=is_p_small[1]=false;
    20     for(LL i=2;i<=N-5;i++){
    21         if(is_p_small[i]){
    22             prime[p++]=i;
    23             for(LL j=2*i;j<=N-5;j+=i) is_p_small[j]=false;
    24         }
    25     }
    26 }
    27 
    28 void sement_sieve(LL a,LL b){
    29     mem(is_p,true);
    30     LL lim=ceil(sqrt(b));
    31     for(LL i=0;prime[i]<=lim;i++){
    32         for(LL j=max(2LL,(a+prime[i]-1)/prime[i])*prime[i];j<=b;j+=prime[i]){
    33             is_p[j-a]=false;
    34             LL res=0;
    35             while(orz[j-a]%prime[i]==0){ 
    36                 orz[j-a]/=prime[i];
    37                 res++;
    38             }
    39             ans[j-a]=ans[j-a]*(res*k+1)%mod;
    40         }
    41      }
    42 }
    43 int main(){
    44     int T;
    45     scanf("%d",&T);
    46     sieve();
    47     while(T--){
    48         scanf("%lld%lld%lld",&l,&r,&k);
    49         for(LL i=0;i<=r-l+5;i++) {ans[i]=1;orz[i]=i+l;}
    50         sement_sieve(l,r+1);
    51         LL sum=0;
    52         for(LL i=0;i<=r-l;i++){
    53             if(orz[i]!=1) ans[i]=ans[i]*(k+1);
    54         }
    55         for(LL i=0;i<=r-l;i++){ 
    56             sum=(sum+ans[i])%mod;
    57         }
    58         printf("%lld
    ",sum);
    59     }
    60     return 0;
    61 }
    View Code
  • 相关阅读:
    C++学习之:括号匹配与栈的使用
    mooc网站以及学习资料收集
    android 获取字符串的方法
    androidStudio中如何加载字体资源?
    BluetoothGatt API
    Android 反编译工具简介
    BluetoothAdapter.LeScanCallback 参考文档
    openCV1
    Android客户端向服务器端发送数据的流程(1)
    将博客搬至CSDN
  • 原文地址:https://www.cnblogs.com/xiaowuga/p/7284074.html
Copyright © 2020-2023  润新知