第四场 hdu 6069 Counting Divisors (逆向思维)

Posted Wally的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四场 hdu 6069 Counting Divisors (逆向思维)相关的知识,希望对你有一定的参考价值。

http://acm.hdu.edu.cn/showproblem.php?pid=6069

题目大意:求 i 从 l 到 r 中 i 的k次方的因子数之和。

解题思路:我们可以知道一个数有因子,则这个数的因子一定是若干个质数因子排列组合得到的。我们首先要得到10^6中的素数,然后它的因子数量是 相同质因子数量+1 的乘积,所以我们能够想到从 l 到 r 枚举每一个i得到其 相同质因子数量+1 的乘积 的累加和。但是这样在枚举时会发现有一些质数是并不是所求的 i 的因子,所以我们应该反过来考虑,对于每一个质因子找出 l 到 r 中它的倍数,这样时间就被缩短了。

AC代码:

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int maxn=1100000;
 5 const long long SMod=998244353;
 6 bool is_prime[maxn+1];
 7 long long  prime[maxn],tmp[maxn],in[maxn];
 8 int sieve(int n)
 9 {
10     int p=0;
11     for(int i=0; i<=n; i++) is_prime[i]=true;
12     is_prime[0]=is_prime[1]=false;
13     for(int i=2; i<=n; i++)
14     {
15         if(is_prime[i])
16         {
17             prime[p++]=i;
18             for(int j=2*i; j<=n; j=j+i)
19                 is_prime[j]=false;
20         }
21     }
22     return p;
23 }
24 int main()
25 {
26     sieve(1000007);
27 //    for(int i=0;i<10;i++)
28 //    printf("%d\n",prime[i]);
29     //freopen("1003.in","r",stdin);
30     //freopen("out.txt","w",stdout);
31     int t;
32     long long l,r,k,ans,cnt,num;
33     scanf("%d",&t);
34     while(t--)
35     {
36         scanf("%lld%lld%lld",&l,&r,&k);
37         int len=r-l;
38         for(int i=0; i<=len; i++)
39         {
40             tmp[i]=1;
41             in[i]=i+l;
42         }
43         ans=0;
44         num=0;
45         for(int i=0; prime[i]*prime[i]<=r&&i<78498; i++)
46         {
47             int p=prime[i];
48             for(int j=l/p*p-l; j<=len; j+=p)
49             {
50                 if(j<0)
51                     continue;
52                 num=0;
53                 while(in[j]%p==0)
54                 {
55                     num++;
56                     in[j]=in[j]/p;
57                 }
58                 tmp[j]=(tmp[j]*(((num*k)%SMod)+1))%SMod;
59             }
60         }
61         for(int i=0; i<=len; i++)
62         {
63             if(in[i]>1)
64                 tmp[i]=(tmp[i]*(k+1))%SMod;
65             //printf("%lld %lld %lld\n",in[i],l+i,tmp[i]);
66             ans=(ans+tmp[i])%SMod;
67             //printf("%lld\n",ans);
68         }
69         printf("%lld\n",ans);
70     }
71     return 0;
72 }

 

 

这个代码挺奇怪的我感觉都对,但是15个数据过了14个就倒数第二个错了郁闷啊>_<||| 。

求大神指点一下

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int maxn=1100000;
 5 const long long SMod=998244353;
 6 bool is_prime[maxn+1];
 7 long long  prime[maxn],tmp[maxn],in[maxn];
 8 int sieve(int n)
 9 {
10     int p=0;
11     for(int i=0; i<=n; i++) is_prime[i]=true;
12     is_prime[0]=is_prime[1]=false;
13     for(int i=2; i<=n; i++)
14     {
15         if(is_prime[i])
16         {
17             prime[p++]=i;
18             for(int j=2*i; j<=n; j=j+i)
19                 is_prime[j]=false;
20         }
21     }
22     return p;
23 }
24 int main()
25 {
26     sieve(1000007);
27 //    for(int i=0;i<10;i++)
28 //    printf("%d\n",prime[i]);
29     //freopen("1003.in","r",stdin);
30     //freopen("out.txt","w",stdout);
31     int t;
32     long long l,r,k,ans,cnt,num;
33     scanf("%d",&t);
34     while(t--)
35     {
36         scanf("%lld%lld%lld",&l,&r,&k);
37         int len=r-l;
38         for(int i=0; i<=len; i++)
39         {
40             tmp[i]=1;
41             in[i]=1;
42         }
43         ans=0;
44         num=0;
45         for(int i=0; prime[i]*prime[i]<=r&&i<78498; i++)
46         {
47             int p=prime[i];
48             int it=prime[i]-(l%prime[i]);
49             if(it==prime[i])
50                 it=0;
51             if(it>len)
52             continue;
53             for(int j=it; j<=len;)
54             {
55                 long long data=j+l;
56                 while(data%p==0)
57                 {
58                     num++;
59                     data=data/p;
60                     in[j]=in[j]*p;
61                 }
62                 if(num!=0)
63                 {
64                     tmp[j]=(tmp[j]*(((num*k)%SMod)+1))%SMod;
65                     num=0;
66                 }
67                 j=j+p;
68             }
69         }
70         for(int i=0; i<=len; i++)
71         {
72             if(in[i]*in[i]<i+l)
73             tmp[i]=tmp[i]*(k+1);
74             //printf("%lld %lld %lld\n",in[i],l+i,tmp[i]);
75             if(l+i==1)
76             {
77                 ans=(ans+1)%SMod;
78             }
79             else if(tmp[i]==1)
80             {
81                 ans=(ans+2)%SMod;
82             }
83             else
84             {
85                 ans=(ans+tmp[i])%SMod;
86             }
87         }
88         printf("%lld\n",ans);
89     }
90     return 0;
91 }

 

以上是关于第四场 hdu 6069 Counting Divisors (逆向思维)的主要内容,如果未能解决你的问题,请参考以下文章

HDU6069 Counting Divisors欧拉筛法

hdu 6069 Counting Divisors(求因子的个数)

hdu 6069 Counting Divisors

HDU 6069 Counting Divisors(唯一分解定理+因子数)

区间筛2-17多校训练四 HDU6069 Counting Divisors

hdu6069 多校Counting Divisors