代码源每日一题
平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:
- 刚开始,派派已经位于某传送阵之上;
- 如果派派掌握一种魔法 (A,B)(A,B),其中 A,BA,B 均为整数。使用一次这个魔法可以让派派从任意整点 (X,Y)(X,Y) 瞬间移动至 (X+A,Y+B)(X+A,Y+B);
- 选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法。
问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?
输入格式
第一行一个整数 NN。
接下来一行 NN 行,每行包含两个整数 Xi,YiXi,Yi, 表示每个魔法阵的坐标。
输出格式
一个数,表示答案。
样例1输入
3
1 1
4 5
1 4
样例1输出
6
解释: 任务是从 (1,1)(1,1) 传送至 (4,5)(4,5) 以及 (1,4)(1,4) 、从 (4,5)(4,5) 传送至 (1,1)(1,1) 以及 (1,4)(1,4) 、从 (1,4)(1,4) 传送至 (1,1)(1,1) 以及 (4,5)(4,5) 。
注意你不能使用 (0,3)+(3,1)(0,3)+(3,1) 的魔法从 (1,1)(1,1) 到达 (4,5)(4,5)。因为每次移动,你只能使用一种魔法。
当然,你可以学习 (0,1)(0,1),那样的话,从 (1,1)(1,1) 到达 (1,4)(1,4) 则需要使用 33 次 (0,1)(0,1) 魔法了。
样例2输入
3
1 1
2 2
1000000000 1000000000
样例2输出
2
数据规模
- N∈[10,500]N∈[10,500]
- Xi,Yi∈[0,109]Xi,Yi∈[0,109], 但保证坐标之间两两不同。
思路:题目让我们求迈的步数种类最少,我们一步跨多大都可以,假设我们现在直接一步迈到指定位置,当点数是倍数时它们可以用相同的步伐大小来到达,所以每一步走的越小越好,我们可以得到两点之间的x,y的差值,因为每一步走的都是相同的,我们改变一步的大小是不会影响能否到达的,那么我们就走最小的距离,假设一步能到达的距离是(2,4),那么我们一步走成(1,2)也是能够到的,我们求出x,y的gcd,然后再除去gcd就能让每一步都最小(x与y是对应的,不用担心(1,3)这类的距离大小)。只要将重复的步伐大小去掉即可。注意x=0,y=0时的情况,就让不为0 的数走成1即可。最后注意一下正负即可,别求出负的gcd,一除成了正数。
map的赋值方法:直接将map的第一个数变成下标,将第二个数赋值给map带下标即可。
pair:有pair时用 {} 大括号包住两个数即可。访问时需要用到 .first 与 .second,引用即可。
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef vector<int> vi;
//#define int long long
#define fir first
#define sec second
#define all(x) (x).begin(), (x).end()
#define sz(x) (int)x.size()
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define repd(i, l, r) for (int i = l; i >= r; --i)
#define pb push_back
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
vector<pii>v;
map<pii,int>mp;
int l,r;
rep(i,1,n)
{
cin>>l>>r;
v.pb({l,r});
}
int ans=0;
rep(i,0,n-1)
{
rep(j,0,n-1)
{
if(i==j)continue;
int x=v[i].fir-v[j].fir;
int y=v[i].sec-v[j].sec;
if(x==0||y==0)
{
x= x!=0 ? x/abs(x):0;
y= y!=0 ? y/abs(y):0;
}
else
{
int num = abs(__gcd(x, y));
x /= num;
y /= num;
}
if(mp[{x,y}]==0)
{
ans++;
mp[{x,y}]=1;
}
}
}
cout<<ans<<endl;
return 0;
}