跳跳-题解
cf 1200
题目描述
平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:
- 刚开始,派派已经位于某传送阵之上;
- 如果派派掌握一种魔法 (A,B),其中 A,B 均为整数。使用一次这个魔法可以让派派从任意整点 (X,Y) 瞬间移动至 (X+A,Y+B);
- 选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法。
问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?
方法:
在到达下一个魔法阵之前只能使用一种魔法,次数没有限制。总共有n个点对,假设我们从任意一点(\(x_1\), \(y_1\)) 到达任意另一点 (\(x_2\), \(y_2\)) 只使用一次魔法,那么就需要一个法术(\(x_2\) - \(x_1\), \(y_2\) - \(y_1\)),从(\(x_2\), \(y_2\)) 到达 (\(x_1\), \(y_1\))需要另一个法术,在此先不考虑,仅考虑“正向”需要的法术,对于任意不同的两点都可以求出一个这样的法术,那么在所有的法术中,有哪些是可以“抵消”的呢?因为一条法术是另一条法术的正整数倍,所以只要比值相同的法术就一定可以用一条“最简比值法术”代替,比如(3,6)和(4,8)虽然他们两个不是倍数关系,但是却可以用“最简比值法术”把他们抵消掉,因此我们的任务就是求比值相同的法术有多少条。前面说先不考虑反向的法术,现在开始考虑,会发现,虽然反向的法术与正向的法术比值相同,但是无法被抵消,因为无法使用负整数次法术,所以只需要考虑正向的然后输出结果的二倍就行了。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 510;
vector<double> v;
PII p[N];
int n;
int main() {
cin >> n;
for(int i = 0; i <n; i++)
cin >> p[i].first >> p[i].second;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(i != j) {
if(p[i].first == p[j].first) //即出现了魔法为(0, x)的情况,可以全部用(0, 1)表示,
v.push_back(1e9); // 用1e9 表示比值避免冲突
else
v.push_back(1.0 * (p[j].second - p[i].second)/(p[j].first - p[i].first));
}
}
}
sort(v.begin(), v.end());
v.erase(v.begin(), unique(v.begin(), v.end()));
cout << v.size() * 2 << endl;
return 0;
}

浙公网安备 33010602011771号