2017 Multi-University Training Contest

来源:互联网 发布:网络教育比函授贵吗 编辑:程序博客网 时间:2024/05/24 06:22

点击打开题目链接

先打表筛选1~1e6内的素数,L,R最多到1e12,然后一个数是素数是这样定义的,如果n是素数,则2~(int)sqrt(n),都不能被n整除。

所以我们筛选素数只需要筛选到sqrt(1e12)范围就好。

其次,任何一个正整数x,都可以分解成若干个素数幂的积。小学学的分解质因子的方法就是这样的。

则 x = (p1^m1)*(p2^m2)*(p3^m3)*.....*(pn^mn);    其中p1,p2,p3...pn都是素数,m1,m2,m3...mn都是幂指数。

则 x 的因子个数d(x) = (m1+1)*(m2+1)*(m3+1)....(mn+1);

这和这些素因子的排列组合有关,举个例子:

例如    12  = 2×2×3

则     12的因子个数为  1 ×(2+1)×(1+1) = 3*2 = 6    

12的因子有: 1   2  3   4  6  12  可以看出答案是正确的。那么为什么会是这样的。

这主要是和这些质因子的组合有关。12 由两个2,和一个3连乘得到

则组合情况有:0个2和0个3乘    1

                         1个2和0个3乘    2

                         2个2和0个3乘    4

                         0个2和1个3乘    3

                         1个2和1个3乘    6

                         2个2和1个3乘   12

对于x^k = ((p1^m1)*(p2^m2)*(p3^m3)*.....*(pn^mn))^k;

       x^k = (p1^m1*k)*(p2^m2*k)*(p3^m3*k)*.....*(pn^mn*k);

则x^k的因子个数d(x^k) = (m1*k+1)*(m2*k+1)*(m3*k+1)*.....*(mn*k+1);    

因为读过《基础数论》这本书,这些结论都知道,就是比赛的时候,求完素数表示,一直都时对每一个数进行分解质因数,

最后导致一直超时,方法不合适,怎么改最后都超时,比赛后看他们都是对某个素数,直接将其倍数直接筛过,这样的确快很多,

只怪自己太笨,不懂得变通,又签到了一场比赛。哭


AC代码:

#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>using namespace std;typedef long long LL;const int mod = 998244353;const int maxn = 1000100;int prime[maxn];  ///素数表LL a[maxn];LL yinzi[maxn];int num;void create_table(){    memset(a,0,sizeof(a));  ///0代表是素数    for(int i = 2; i <= sqrt(maxn); i++)    {        for(int j = 2*i; j <= maxn; j+=i)        {                if(a[j]==0)                    a[j] = 1;        }    }    num = 0;    for(int i = 2; i <= maxn; i++)    {        if(a[i]==0)        {            prime[num++] = i;        }    }}/**由于left和right值比较大,所以存他们的相关信息存不下,而left和right差距不超过1e6,因此hash一下,将其散列到0~1e6内**/void Hash(LL left,LL right){    ///    for(LL i = left; i <= right; i++)    {        yinzi[i-left] = 1;        a[i-left] = i;    }}void solve(LL left,LL right,int k){    for(int i = 0; i<num && prime[i]<=sqrt(right*1.0); i++)    {        LL start,ccount;        if(left%prime[i]==0) start = left;        else start = left/prime[i]*prime[i]+prime[i];  ///求起点        for(LL j = start; j <= right; j += prime[i])        {            ccount = 0;  ///记录prime[i]的幂            while(a[j-left]%prime[i]==0)            {                ccount++;                a[j-left] = a[j-left]/prime[i];            }            yinzi[j-left] = ((yinzi[j-left]%mod)*((ccount*k+1)%mod))%mod;        }    }    LL ans = 0;    for(int i = 0; i <= right-left; i++)    {        if(a[i]!=1)  ///代表是素数        {            ans = (ans+(yinzi[i]*(k+1))%mod)%mod;        }        else        {            ans = (ans+yinzi[i])%mod;        }    }    cout<<ans<<endl;}int main(){   int t,k;   LL left,right;   create_table();  ///打素数表   cin>>t;   while(t--)   {       cin>>left>>right>>k;       Hash(left,right);       solve(left,right,k);   }   return 0;}





原创粉丝点击