第四场 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 }
时间: 2024-10-11 14:34:30

第四场 hdu 6069 Counting Divisors (逆向思维)的相关文章

HDU 6069 Counting Divisors —— 2017 Multi-University Training 4

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 2599    Accepted Submission(s): 959 Problem Description In mathematics, the function d(n) denotes the number of divisors of p

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

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 3170    Accepted Submission(s): 1184 Problem Description In mathematics, the function d(n) denotes the number of divisors of

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

http://acm.hdu.edu.cn/showproblem.php?pid=6069 题意: 思路: 根据唯一分解定理,$n={a_{1}}^{p1}*{a2_{}}^{p2}...*{a_{m}}^{pm}$,那么n的因子数就是 n的k次方也是一样的,也就是p前面乘个k就可以了. 先打个1e6范围的素数表,然后枚举每个素数,在[ l , r ]寻找该素数的倍数,将其分解质因数. 到最后如果一个数没有变成1,那就说明这个数是大于1e6的质数.(它就只有0和1两种选择) 1 #includ

HDU 6069 Counting Divisors(区间素数筛法)

题意:...就题面一句话 思路:比赛一看公式,就想到要用到约数个数定理 约数个数定理就是: 对于一个大于1正整数n可以分解质因数: 则n的正约数的个数就是 对于n^k其实就是每个因子的个数乘了一个K 然后现在就变成了求每个数的每个质因子有多少个,但是比赛的时候只想到sqrt(n)的分解方法,总复杂度爆炸,就一直没过去,然后赛后看官方题解感觉好妙啊! 通过类似素数筛法的方式,把L - R的质因子给分解,就可以在O(nlogn)的时间之内把所以的数给筛出来. 代码: /** @xigua */ #i

hdu 6069 Counting Divisors

题意:给出求L,R 之间的数的K次方的因子数之和 思路:打表求出1~10^6之间的素数,枚举[L,R]之间素数的倍数,然后按算数基本定理求出因子个数和.处理过后[L,R]之间的数要么是1,要么是一个素数,再次根据算数基本定理计算因子个数和. #include<bits/stdc++.h> #define MAXSIZE 1000015 #define INF 0x3f3f3f3f #define LL long long #define MOD 998244353 using namespac

第四场 hdu 6070 Dirt Ratio (线段树+二分)

http://acm.hdu.edu.cn/showproblem.php?pid=6070 题目大意:给出的序列上的数代表颜色,求子序列中不同数字的个数X与子序列长度Y中,X/Y的最小值 解题思路:思路和官方给的想法一样 值得注意的是线段树的节点中储存的是 size(l,r)+mid×l ,在建树时 mid×l 作为树节点的初始值,然后不断更新当前颜色对于 前一个相同颜色的位置+1 到 当前位置 的节点值+1,然后询问 1 到 当前位置的最小值 是否小于mid*(i+1). 虽然最后要打印小数

Counting Divisors HDU - 6069

Counting Divisors HDU - 6069 题意:给定区间[a,b]和k,求xk有多少因子(x属于[a,b]),求和. 题解:http://blog.csdn.net/zlh_hhhh/article/details/76680641 a.b最大可达到1e12,但是b-a<1e6. 一开始愚蠢的一个一个分解然后去求有多少因子然后求和,范围那么大裸裸的超时啊! 可以枚举素数,对每一个素数,把区间内所有可以分解的进行分解. 最后再求和. 1 #include <bits/stdc++

[hdu 4899]14年多校第四场C Hero meet devil 状压DP

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 122    Accepted Submission(s): 49 Problem Description There is an old country and the king fell in love with a devil. The devil always asks th

2014多校第四场1005 || HDU 4901 The Romantic Hero (DP)

题目链接 题意 :给你一个数列,让你从中挑选一些数组成集合S,挑另外一些数组成集合T,要求是S中的每一个数在原序列中的下标要小于T中每一个数在原序列中下标.S中所有数按位异或后的值要与T中所有的数按位与的值相同,问能找出多少符合要求的组合. 思路 :比赛的时候有点没有头绪,后来二师兄想出了状态转移方程,YN又改了很多细节,最后才A的.总之是个别扭的DP..... 一开始是 _xor[i][j^a[i]] += _xor[i-1][j] :j 的下一个状态 就是异或上a[i],这个数组所代表的意思