[UVALive 6955 Finding Lines]概率+随机算法
知识点:math
probability
random algorithm
1. 题目链接
2. 题意描述
有
n
个顶点,坐标记为
1≤n≤105,0≤xi,yi≤109,20≤p≤100
。
3. 解题思路
比较直接的想法是
O(N2)
的去暴力枚举。显然不行。
但是,注意到这个题目
20≤p≤100
这个条件。细细分析一下。需要有一条直线覆盖
20%
的点,在点完全均匀离散的时候,实际上概率是比较小的。
考虑随机选取
2
个顶点来枚举每条直线。假设存在
随机次数
t
的确定可以这样做:
取
[1−(p100)2]t=(2425)t
我们可以取 t∈[200,1000] 。太大了会TLE,因为每次需要 O(n) 的统计在直线上的点。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
int n, p;
LL x[MAXN], y[MAXN];
bool ans;
void run() {
int a = rand() % n;
int b = rand() % n;
while(b == a) b = rand() % n;
LL up = x[a] - x[b], dw = y[a] - y[b];
LL cnt = 2;
for(int i = 0; i < n; i++) {
if(i == a || i == b) continue;
LL uup = x[i] - x[b], ddw = y[i] - y[b];
if(up * ddw == uup * dw) cnt ++;
}
if(n * p <= cnt * 100) ans = true;
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
srand(12);
while(~scanf("%d", &n)) {
scanf("%d", &p);
ans = false;
for(int i = 0; i < n; i++) scanf("%lld %lld", &x[i], &y[i]);
if(n <= 2) {
puts("possible");
continue;
}
int t = 200;
while(t --) {
run();
if(ans) break;
}
puts(ans ? "possible" : "impossible");
}
return 0;
}