题目链接:https://codeforces.com/contest/1305/problem/F 这是一道很神仙的题 算法就是我们一般不常用的随机化
我们发现,这个玩意的操作上线是
n
n
n,只要以
2
2
2作为最终的
G
C
D
GCD
GCD即可
此时,也就是说操作次数
>
=
2
>=2
>=2的数的个数
<
=
n
/
2
<=n/2
<=n/2,于是我们可以想到随机化,我们先打乱整个序列,然后从中选出前
100
100
100个数,认为它们只操作不超过一次。
由于随机选出一个数操作次数大于等于
2
2
2的概率不超过
1
/
2
1/2
1/2,也就是说挂掉的概率大概为
1
2
100
\frac{1}{2^{100}}
21001
最后一点要强调的是,我们随机的时候要打乱序列,否则很可能会像我一样被出题人"善意"的数据卡掉
随机数
5224999
5224999
5224999万岁!!! 随机数
5224999
5224999
5224999万岁!!! 随机数
5224999
5224999
5224999万岁!!!
C
o
d
e
Code
Code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
using namespace std
;
#define int long long
#define max(a, b) a > b? a : b
#define min(a, b) a < b? a : b
const int MAXN
= 2e5, MAXP
= 1e6;
int a
[MAXN
+ 10], num
[MAXN
+ 10], top
= 0;
int prime
[MAXP
+ 10], vis
[MAXP
+ 10], tot
= 0;
inline int read();
void euler(int n
){
for (register int i
= 2; i
<= n
; ++i
){
if (!vis
[i
]){prime
[++tot
] = i
, vis
[i
] = i
;}
for (register int j
= 1; j
<= tot
&& prime
[j
] * i
<= n
; ++j
){
if (prime
[j
] > vis
[i
]) break;
vis
[i
* prime
[j
]] = prime
[j
];
}
}
}
void get_prime(int n
){
for (register int i
= 1; i
<= tot
&& prime
[i
] * prime
[i
] <= n
; ++i
){
if (n
% prime
[i
] == 0){
if (!vis
[i
]) num
[++top
] = prime
[i
], vis
[i
] = 1;
while (n
% prime
[i
] == 0) n
/= prime
[i
];
}
}
if (n
> 1) num
[++top
] = n
;
}
int get_ans(int x
, int n
){
int ans
= 0;
for (register int i
= 1; i
<= n
; ++i
){
int sum
= min(a
[i
] % x
, x
- a
[i
] % x
);
if (a
[i
] < x
) sum
= x
- a
[i
];
ans
+= sum
;
}
cerr
<< x
<< " " << ans
<< endl
;
return ans
;
}
signed main(){
freopen
("std.in", "r", stdin);
freopen
("std.out", "w", stdout);
srand(time(0) * 5224999);
int n
= read(), ans
= 2e5; euler(1e6);
memset(vis
, 0, sizeof(vis
));
for (register int i
= 1; i
<= n
; ++i
) a
[i
] = read();
random_shuffle(a
+ 1, a
+ n
+ 1); int mx
= min(n
, 100);
for (register int i
= 1; i
<= mx
; ++i
){
get_prime(a
[i
]), get_prime(a
[i
] - 1), get_prime(a
[i
] + 1);
}
for (register int i
= 1; i
<= top
; ++i
)
ans
= min(ans
, get_ans(num
[i
], n
));
printf("%lld\n", ans
);
return 0;
}
inline int read(){
int x
= 0;
char c
= getchar();
while (!isdigit(c
))c
= getchar();
while (isdigit(c
))x
= (x
<< 1) + (x
<< 3) + (c
& 15), c
= getchar();
return x
;
}