[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\n", Ans);
    }
    return 0;
}

  

时间: 2024-08-08 17:54:43

[HDOJ 5212] [BestCoder Round#39] Code 【0.0】的相关文章

Code( BestCoder Round #39 ($) C) (莫比乌斯反演)

Code Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 209    Accepted Submission(s): 85 Problem Description WLD likes playing with codes.One day he is writing a function.Howerver,his computer br

暴力+降复杂度 BestCoder Round #39 1002 Mutiple

题目传送门 1 /* 2 设一个b[]来保存每一个a[]的质因数的id,从后往前每一次更新质因数的id, 3 若没有,默认加0,nlogn复杂度: 4 我用暴力竟然水过去了:) 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <cstring> 9 #include <string> 10 #include <algorithm> 11 using namespace std;

贪心 BestCoder Round #39 1001 Delete

题目传送门 1 /* 2 贪心水题:找出出现次数>1的次数和res,如果要减去的比res小,那么总的不同的数字tot不会少: 3 否则再在tot里减去多余的即为答案 4 用set容器也可以做,思路一样 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <cstring> 9 #include <string> 10 #include <algorithm> 11 using

POJ1850 Code 【排列组合】

还不算是难题(嘿嘿,因为我做出来了) 很简单,找到相应的方程式解就是了(中间也犯了一个很2的错误,把9+10+11+...+99写成(1+90)*90/2,改过来后就好了) 不多说,code is below #include <iostream> #include <cstdio> #include <cstring> using namespace std; int combi(int a,int b) { int sum=1; int j=1; for(int i

hdoj 2095 find your present (2) 【位运算】

题意:找出现次数不同于其他数的数. 超时了一次,后来知道了位运算...长见识了 0^0 =0 0^1=1 1^0=1 1^1=0 0^1^1 = 0 可以发现 任何数异或0还是他本身. 一个数异或另一个数偶数次还是他本身. 代码(位运算都600+ms): #include <stdio.h> #include <math.h> int main() { int a, b, n; while(scanf("%d", &n), n){ scanf("

hdoj 2191 悼念512。。 【多重背包】+【二进制分解】

话说题目真长... 题意: 中文题,你懂得.. 策略:多重背包问题.多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用2的次幂分解成若干个件数的集合,这里面数字可以组合成任意小于等于C的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可 以用数字的二进制形式来解释     比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以 组合成任意小于等于7 的数,而且每种组合都会得到不同的数.     15 = 1111 可分解成 0001  0010 

SpringBoot2整合Shiro报错 UnavailableSecurityManagerException: No SecurityManager accessible to the calling code 【已解决】

SpringBoot集成Shiro报错 UnavailableSecurityManagerException: No SecurityManager accessible to the calling code [已解决] 调试了好久,网上找了很多方法,,哎,太特么难受了,当知道原因的时候,,一万只草泥马在奔腾... 废话不多说,言归正传: 1.报错日志信息 org.apache.shiro.UnavailableSecurityManagerException: No SecurityMan

[BestCoder Round#26] Apple 【组合数学】

题目链接:HDOJ - 5160 题目分析 第一眼看上去,要求统计所有不同排列对答案的贡献.嗯...完全没有想法. 但是,如果我们对每个数字单独考虑,计算这个数字在总答案中的贡献,就容易多了. 对于一个数字 ai ,有 ni 个 .比它大的数字有 p 个,比它小的数字有 q 个.所有的数字一共有 N 个. 首先,比它小的数字对它不会造成影响,所以我们只要考虑它和比它大的数字.那么我们就在 N 个位置中,选 (ni + p) 个位置,给它和比它大的数字. 然后比它大的数字有 x1 种排列,比它小的

poj 2449 Remmarguts&amp;#39; Date 【SPFA+Astar】【古典】

称号:poj 2449 Remmarguts' Date 意甲冠军:给定一个图,乞讨k短路. 算法:SPFA求最短路 + AStar 以下引用大牛的分析: 首先,为了说话方便,列出一些术语: 在启示式搜索中,对于每一个状态 x.启示函数 f(x) 一般是这种形式: f(x) = g(x) + h(x) 当中 g(x) 是从初始状态走到 x 所花的代价:h(x) 是从 x 走到目标状态所须要的代价的预计值. 相对于 h(x).另一个概念叫 h*(x),表示从 x 走到目标状态所须要的实际最小代价(