题目链接
简单版本
直接统计答案,数目到达一半即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
int n;
int a, b, c, d;
pair <int, int> ans;
map <pair <int, int >, int > mp;
int main(){
scanf("%d", &n);
rep(i, 1, n){
scanf("%d%d%d%d", &a, &b, &c, &d);
++mp[{c - a, d - b}];
if (mp[{c - a, d - b}] >= (n + 1) / 2) ans = {c - a, d - b};
}
printf("%d %d\n", ans.first, ans.second);
return 0;
}
中等版本
题面和简单版本不一样。
我们可以通过两组变化解出一组行人的移动参数
具体的解法是
scale可以通过变换后两点之间距离的倍数关系求出
旋转坐标前两个点形成的直线向量A,和旋转坐标后的两个点形成的直线向量B
那么θ就是A,B的夹角,然后用一下公式$cosθ=\frac{A*B}{|A|*|B|}$, 就能算出角度了。
那么dx, dy就很好求了。
我们两两枚举所有的变化,求出参数,然后验证一下在n组变化中吻合次数是否到达一半。
(注意eps要开1e-4,我之前开了1e-8一直WA)
时间复杂度$O(n^3)$
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
const int N = 1e5 + 10;
const double eps = 1e-4;
struct node{
double x, y;
void scan() { scanf("%lf%lf", &x, &y); }
void print(){ printf("%.12f %.12f\n", x, y); }
friend node operator - (const node &a, const node &b){
return node{a.x - b.x, a.y - b.y};
}
friend node operator + (const node &a, const node &b){
return node{a.x + b.x, a.y + b.y};
}
friend bool operator == (const node &a, const node &b){
return fabs(a.x - b.x) < eps && fabs(a.y - b.y) < eps;
}
} a[N], b[N];
struct Node{
double cita, scale, dx, dy;
void print(){ printf("%.12f\n%.12f\n%.12f %.12f\n", cita, scale, dx, dy); }
} ret;
int n;
double dis(const node &a, const node &b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double angle(const node &a){
return atan2(a.y, a.x);
}
node calc(double ang, node a){
double x = a.x, y = a.y;
a.x = x * cos(ang) - y * sin(ang);
a.y = x * sin(ang) + y * cos(ang);
return a;
}
bool judge(Node cnt){
int ret = 0;
node now;
rep(i, 1, n){
now = calc(cnt.cita, a[i]);
now.x *= cnt.scale;
now.y *= cnt.scale;
now.x += cnt.dx;
now.y += cnt.dy;
if (now == b[i]) continue;
++ret;
if (ret * 2 > n) return false;
}
return true;
}
Node solve(int x, int y){
Node ret = {0, 0, 0, 0};
ret.cita = angle(b[y] - b[x]) - angle(a[y] - a[x]);
ret.scale = dis(b[x], b[y]) / dis(a[x], a[y]);
node cnt = calc(ret.cita, a[x]);
ret.dx = b[x].x - ret.scale * cnt.x;
ret.dy = b[x].y - ret.scale * cnt.y;
return ret;
}
int main(){
scanf("%d", &n);
rep(i, 1, n){
a[i].scan();
b[i].scan();
}
if (n == 1){
puts("0.000000000000");
puts("1.000000000000");
node c = b[1] - a[1];
c.print();
return 0;
}
bool flag = false;
rep(i, 1, n - 1){
rep(j, i + 1, n){
ret = solve(i, j);
if (judge(ret)){
flag = true;
break;
}
}
if (flag) break;
}
ret.print();
return 0;
}
困难版本
因为错误的参数不超过一半,那么我们选择一个点,他的参数错误的概率不超过0.5
所以我们选择两个点,这两个点至少有一个点的参数错误的概率不超过0.75
我们随机枚举100次,那么枚举得到的的100组参数都错的概率为$0.75^{100}$,几乎为0
但是中等的代码交到困难版本这边是TLE的,为什么呢。
因为中等的代码是有序枚举的,如果前面很多的点参数都是错的,那么就枚举不到正确答案,于是就TLE了。
时间复杂度$O(100n)$
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
const int N = 1e5 + 10;
const double eps = 1e-4;
struct node{
double x, y;
void scan() { scanf("%lf%lf", &x, &y); }
void print(){ printf("%.12f %.12f\n", x, y); }
friend node operator - (const node &a, const node &b){
return node{a.x - b.x, a.y - b.y};
}
friend node operator + (const node &a, const node &b){
return node{a.x + b.x, a.y + b.y};
}
friend bool operator == (const node &a, const node &b){
return fabs(a.x - b.x) < eps && fabs(a.y - b.y) < eps;
}
} a[N], b[N];
struct Node{
double cita, scale, dx, dy;
void print(){ printf("%.12f\n%.12f\n%.12f %.12f\n", cita, scale, dx, dy); }
} ret;
int n;
double dis(const node &a, const node &b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double angle(const node &a){
return atan2(a.y, a.x);
}
node calc(double ang, node a){
double x = a.x, y = a.y;
a.x = x * cos(ang) - y * sin(ang);
a.y = x * sin(ang) + y * cos(ang);
return a;
}
bool judge(Node cnt){
int ret = 0;
node now;
rep(i, 1, n){
now = calc(cnt.cita, a[i]);
now.x *= cnt.scale;
now.y *= cnt.scale;
now.x += cnt.dx;
now.y += cnt.dy;
if (now == b[i]) continue;
++ret;
if (ret * 2 > n) return false;
}
return true;
}
Node solve(int x, int y){
Node ret = {0, 0, 0, 0};
ret.cita = angle(b[y] - b[x]) - angle(a[y] - a[x]);
ret.scale = dis(b[x], b[y]) / dis(a[x], a[y]);
node cnt = calc(ret.cita, a[x]);
ret.dx = b[x].x - ret.scale * cnt.x;
ret.dy = b[x].y - ret.scale * cnt.y;
return ret;
}
int main(){
scanf("%d", &n);
rep(i, 1, n){
a[i].scan();
b[i].scan();
}
if (n == 1){
puts("0.000000000000");
puts("1.000000000000");
node c = b[1] - a[1];
c.print();
return 0;
}
rep(Case, 1, 100){
int x = rand() % n + 1;
int y = rand() % n + 1;
if (x == y) continue;
ret = solve(x, y);
if (judge(ret)) break;
}
ret.print();
return 0;
}