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 }
时间: 2024-08-04 10:42:34

BZOJ 1968 [Ahoi2005]COMMON 约数研究:数学【思维题】的相关文章

BZOJ 1968: [Ahoi2005]COMMON 约数研究

1968: [Ahoi2005]COMMON 约数研究 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 2032  Solved: 1537[Submit][Status][Discuss] Description Input 只有一行一个整数 N(0 < N < 1000000). Output 只有一行输出,为整数M,即f(1)到f(N)的累加和. Sample Input 3 Sample Output 5 HINT Source Day2 [

BZOJ 1968: [Ahoi2005]COMMON 约数研究(新生必做的水题)

1968: [Ahoi2005]COMMON 约数研究 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 2351  Solved: 1797 [Submit][Status][Discuss] Description Input 只有一行一个整数 N(0 < N < 1000000). Output 只有一行输出,为整数M,即f(1)到f(N)的累加和. Sample Input 3 Sample Output 5 HINT Source Day2

BZOJ 1968: [Ahoi2005]COMMON 约数研究 水题

1968: [Ahoi2005]COMMON 约数研究 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1968 Description Input 只有一行一个整数 N(0 < N < 1000000). Output 只有一行输出,为整数M,即f(1)到f(N)的累加和 Sample Input 3 Sample Output 5 HINT 题意 题解:

BZOJ 1968 AHOI2005 COMMON 约数研究 线性筛

题目大意:求n以内所有数的约数个数和 100W,n√n别想了 线性筛可以处理,对于每个数记录最小质因数的次数 令factoral[i]为i的因数个数 cnt[i]为i的最小质因数的次数 若i为质数 则factoral[i]=2 cnt[i]=1 若i%prime[j]!=0 则factoral[prime[j]*i]=factorial[i]*2 cnt[prime[j]*i]=1 若i%prime[j]==0 则factorial[prime[j]*i]=factorial[i]/(cnt[i

1968: [Ahoi2005]COMMON 约数研究

1 #include<cstdio> 2 #include<iostream> 3 #define M 1000008 4 using namespace std; 5 long long tot,f[M],sum[M],ans,n,b[M],p[M]; 6 int main() 7 { 8 scanf("%d",&n); 9 ans=1; 10 for(int i=2;i<=n;i++) 11 { 12 if(!b[i]) 13 { 14 tot

BZOJ1968: [Ahoi2005]COMMON 约数研究(数论 水题)

Description Input 只有一行一个整数 N(0 < N < 1000000). Output 只有一行输出,为整数M,即f(1)到f(N)的累加和. Sample Input 3 Sample Output 5 Solve: 数论水题,求因数又不是质因数,所以,只要求出对于[1 , n]有多少个倍数,就表示[1 , n]中以i为因数的是哪些,加起来就可以了 Code: 1 #include <bits/stdc++.h> 2 using namespace std;

bzoj千题计划170:bzoj1968: [Ahoi2005]COMMON 约数研究

http://www.lydsy.com/JudgeOnline/problem.php?id=1968 换个角度 一个数可以成为几个数的约数 #include<cstdio> #include<iostream> using namespace std; int main() { int n; long long ans=0; scanf("%d",&n); for(int i=1;i<=n;++i) ans+=n/i; cout<<

BZOJ1968 [Ahoi2005]COMMON 约数研究

Description Input 只有一行一个整数 N(0 < N < 1000000). Output 只有一行输出,为整数M,即f(1)到f(N)的累加和. Sample Input 3 Sample Output 5 HINT Source Day2 正解:数学 解题报告: 讨论每个因子的贡献就可以了. 1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include &l

【数论】bzoj1968 [Ahoi2005]COMMON 约数研究

对于i属于[1,n],i只能成为[1,n]中n/i个数的约数,易证. 1 #include<stdio.h> 2 int n,i; 3 long long ans; 4 int main() 5 { 6 scanf("%d",&n); 7 for(i=1;i<=n;i++)ans+=(long long)n/i; 8 printf("%lld\n",ans);return 0; 9 }