所谓的日常 #2 - 張翼德怒鞭督郵 何國舅謀誅宦豎
div.2
给定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 }
div.1
给定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 }