zoukankan      html  css  js  c++  java
  • [HDOJ 5212] [BestCoder Round#39] Code 【0.0】

    题目链接:HDOJ - 5212

    题目分析

    首先的思路是,考虑每个数对最终答案的贡献。

    那么我们就要求出:对于每个数,以它为 gcd 的数对有多少对。

    显然,对于一个数 x ,以它为 gcd 的两个数一定都是 x 的倍数。如果 x 的倍数在数列中有 k 个,那么最多有 k^2 对数的 gcd 是 x 。

    同样显然的是,对于两个数,如果他们都是 x 的倍数,那么他们的 gcd 一定也是 x 的倍数。

    所以,我们求出 x 的倍数在数列中有 k 个,然后就有 k^2 对数满足两个数都是 x 的倍数,这 k^2 对数的 gcd,要么是 x ,要么是 2x, 3x, 4x...

    并且,一个数是 x 的倍数的倍数,它就一定是 x 的倍数。所以以 x 的倍数为 gcd 的数对,一定都包含在这 k^2 对数中。

    如果我们从大到小枚举 x ,这样计算 x 的贡献时,x 的多倍数就已经计算完了。我们用 f(x) 表示以 x 为 gcd 的数对个数。

    那么 f(x) = k^2 - f(2x) - f(3x) - f(4x) ... f(tx)             (tx <= 10000, k = Cnt[x])

    这样枚举每个 x ,然后枚举每个 x 的倍数,复杂度是用调和级数计算的,约为 O(n logn)。 

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <queue>
    
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef double LF;
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    inline int gmax(int a, int b) {return a > b ? a : b;}
    
    inline LF gmin(LF a, LF b) {return a < b ? a : b;}
    inline LF gmax(LF a, LF b) {return a > b ? a : b;}
    
    const LF Eps = 1e-8;
    
    inline LF Sqr(LF x) {return x * x;}
    
    inline int Sgn(LF x)
    {
        if (x < -Eps) return -1;
        if (x > Eps) return 1;
        return 0;    
    }
    
    const int MaxN = 10000 + 5, Mod = 10007;
    
    int n, Ans, Num, Temp, SqrtX;
    int Cnt[MaxN], f[MaxN], Pos[MaxN];
    
    int main()
    {
        while (scanf("%d", &n) != EOF)
        {
        	for (int i = 1; i <= 10000; ++i) Cnt[i] = 0;
           	for (int i = 1; i <= n; ++i) 
           	{
        		scanf("%d", &Num);
        		SqrtX = (int)sqrt((LF)Num);
        		for (int j = 1; j <= SqrtX; ++j)
        		{
        			if (Num % j != 0) continue;
    				++Cnt[j];
        			if (Num / j != j) ++Cnt[Num / j];
        		}
           	}
           	Ans = 0;
           	for (int i = 10000; i >= 1; --i)
           	{
           		f[i] = Cnt[i] * Cnt[i] % Mod;
           		for (int j = i * 2; j <= 10000; j += i)
           			f[i] = (f[i] - f[j] + Mod) % Mod;
           		Temp = i * (i - 1) % Mod;
           		Ans = (Ans + f[i] * Temp % Mod) % Mod;
           	}
            printf("%d
    ", Ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Java程序员从笨鸟到菜鸟全部博客目录
    Problem I
    Problem I
    Problem S
    Problem S
    Problem X
    Problem X
    Problem Q
    Problem Q
    Ellipse
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4458629.html
Copyright © 2011-2022 走看看