BZOJ 1968 [Ahoi2005]COMMON 约数研究:数学思维题

Posted Leohh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1968 [Ahoi2005]COMMON 约数研究:数学思维题相关的知识,希望对你有一定的参考价值。

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1968

题意:

  设f(x) = x约数的个数。如:12的约数有1,2,3,4,6,12,所以f(12) = 6。

  给定n,问你f(1)到f(n)之和。

 

题解:

  好多做法。。。

  (1)O(N*sqrt(N))

      纯暴力(应该过不了)。

      枚举i,sqrt(i)复杂度求出约数个数,更新ans。

      不附代码。

 

  (2)O(N*log(N))

      若当前枚举到i,则i为i*k的一个约数(k >= 0),dp[i*k]++。

      先枚举i,再枚举i*k,复杂度 = n * (1 + 1/2 + 1/3 + 1/4 +...+ 1/n) = N*log(N)

 

  (3)O(N)

      转化问题:

        设g(x) = [1,n]中x倍数的个数。

        ans = ∑ g(i)

      显然有g(x) = floor(n/x),O(1)算出。

      枚举i,ans += g(i),复杂度O(N)。

 

  (4)O(sqrt(N))

      延续(3)的思路。

      显然,对于数列g(x),你会发现有一些区间内的数都是一样的。

      那么哪些g(x)会是相同的呢?

        假如现在枚举到了i。

        由于 g(x) = floor(n/i)

        所以有 n/i = g(i) ... P(余数)

        那么现在想求出这段区间的末尾位置j,即求出满足n/j = g(i) ... P,显然当P(余数)越接近0时,j越大。

        所以当P约等于0时,末尾位置j = floor(n/g(i)) = floor(n/floor(n/i))。

        所以下一个区间的起始位置为j+1。

      所以对于处理的每个i,要将ans += (j-i+1) * g(i)

      复杂度 = 不同的floor(n/i)的个数 = sqrt(N)

 

  看下效率差距。。。(从下往上为算法2,3,4)

  

 

 

AC Code(2):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 1000005
 5 
 6 using namespace std;
 7 
 8 int n;
 9 int ans=0;
10 int dp[MAX_N];
11 
12 int main()
13 {
14     cin>>n;
15     memset(dp,0,sizeof(dp));
16     for(int i=1;i<=n;i++)
17     {
18         for(int j=i;j<=n;j+=i)
19         {
20             dp[j]++;
21         }
22         ans+=dp[i];
23     }
24     cout<<ans<<endl;
25 }

 

AC Code(3):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 
 5 using namespace std;
 6 
 7 int n;
 8 int ans=0;
 9 
10 int main()
11 {
12     cin>>n;
13     for(int i=1;i<=n;i++)
14     {
15         ans+=n/i;
16     }
17     cout<<ans<<endl;
18 }

 

AC Code(4):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 
 5 using namespace std;
 6 
 7 int n;
 8 int ans=0;
 9 
10 int main()
11 {
12     cin>>n;
13     for(int i=1,j=1;i<=n;i=j+1)
14     {
15         j=n/(n/i);
16         ans+=(j-i+1)*(n/i);
17     }
18     cout<<ans<<endl;
19 }

 

以上是关于BZOJ 1968 [Ahoi2005]COMMON 约数研究:数学思维题的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1968: [Ahoi2005]COMMON 约数研究

BZOJ 1968: [Ahoi2005]COMMON 约数研究

BZOJ-1968: [Ahoi2005]COMMON 约数研究 (思想)

BZOJ 1968 [Ahoi2005]COMMON 约数研究

[bzoj1968][Ahoi2005]COMMON 约数研究

BZOJ1968AHoi2005COMMON约数研究