所谓的日常 #2 - 張翼德怒鞭督郵 何國舅謀誅宦豎

div.2

CodeForces 567A Lineland Mail

给定x轴上n(<=1e5)个点的坐标(从小到大),问每个点到其最近点和最远点的距离分别是多少。

当然n ^ 2是不可以通过的...因为跑得太慢了。一般来讲,计算机1秒可以执行10的8次方左右的操作次数,而n^2 = 10的10次方...

因为给出的数组已经是升序了,所以对于一个点来说,最近点一定是左边和右边临近的一个,最远点则是最左和最右中的一个。

 然后min函数和max函数在algorithm头文件里有。

 1 #include <stdio.h>
 2 #include <algorithm>
 3 
 4 const int N = 100000 + 5;
 5 int n,A[N];
 6 
 7 int main() {
 8     scanf("%d",&n);
 9     for (int i = 0; i < n; ++ i) {
10         scanf("%d",A + i);
11     }
12     for (int i = 0; i < n; ++ i) {
13         if (i == 0) {
14             printf("%d %d\n",A[1] - A[0],A[n - 1] - A[0]);
15         } else if (i == n - 1) {
16             printf("%d %d\n",A[n - 1] - A[n - 2],A[n - 1] - A[0]);
17         } else {
18             printf("%d %d\n",std::min(A[i] - A[i - 1],A[i + 1] - A[i]),std::max(A[i] - A[0],A[n - 1] - A[i]));
19         }
20     }
21 }
View Code

 

div.1

CodeForces 364D Ghd

给定n(<= 1e6)个整数(<= 1e12),找到一个最大的整数x,使得x是n个数中的至少一半数的约数。

考虑这么一件事情,假如我们知道答案是x,那么从n个数里随机选出一个数y,x是y的约数的概率为1/2。

那么随机选10次,x是这10个数中的至少一个数的约数的概率为(1 - 0.5^10) = 0.9990234375,基本认为必中。

那么做法就是 随机K(K取10)次,每次从n个数中随机选出一个数,枚举它的全部约数,判断该约数是否出现了足够多次,是的话更新一下答案。

然后我们知道一个整数A的约数数量约是O(log(A)^2)级别的,所以判断的部分平方枚举两个约数log(A)^4,千万级别。

我实现的代码复杂度为O(K *  (sqrt(A) + nlog(log(A)^2) + log(A)^4)),大约2e8。

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 
 4 const int N = 1000000 + 5;
 5 LL A[N],B[N];
 6 int n,tot,cnt[N];
 7 
 8 LL gcd(LL a,LL b) {
 9     return b == 0 ? a : gcd(b,a % b);
10 }
11 
12 LL work() {
13     LL ret = 1;
14     for (int step = 0; step < 10; ++ step) {
15         LL val = A[(rand() << 15 | rand()) % n];
16         tot = 0;
17         for (LL i = 1; i * i <= val; ++ i) {
18             if (val % i == 0) {
19                 B[tot++] = i;
20                 if (i != val / i) {
21                     B[tot++] = val / i;
22                 }
23             }
24         }
25         std::sort(B,B + tot);
26         std::fill(cnt,cnt + tot,0);
27         for (int i = 0; i < n; ++ i) {
28             cnt[std::lower_bound(B,B + tot,gcd(A[i],val)) - B] ++;
29         }
30         for (int i = tot - 1; i >= 0; -- i) {
31             if (B[i] <= ret) break;
32             int sum = 0;
33             for (int j = i; j < tot; ++ j) {
34                 if (B[j] % B[i] == 0)
35                     sum += cnt[j];
36             }
37             if (sum * 2 >= n) {
38                 ret = B[i];
39             }
40         }
41     }
42 
43     return ret;
44 }
45 
46 int main() {
47     srand(time(NULL));
48     scanf("%d",&n);
49     for (int i = 0; i < n; ++ i) {
50         scanf("%I64d",A + i);
51     }
52     printf("%I64d\n",work());
53 }
View Code

 

posted @ 2015-12-19 20:23  zstuACM  阅读(262)  评论(0编辑  收藏  举报