专栏文章
P8042 [COCI 2016/2017 #7] PARALELOGRAMI 详解
P8042题解参与者 2已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @minrifys
- 此快照首次捕获于
- 2025/12/02 07:10 3 个月前
- 此快照最后确认于
- 2025/12/02 07:10 3 个月前
思路
先说明一下,这里的第一象限不是数学意义上的第一象限,也就是点在坐标轴上也算是在第一象限,下文的第一象限全部是这个定义。
若所有点在第一象限,不需要操作。
讨论无解的情况,很明显若不能移动则无解,所以我们只需要判断能不能找出不共线的两个点就可以了。
那其他有没有无解的情况呢?答案是没有,因为这个平行四边形可以覆盖到整个坐标系,可能有点抽象,放一个官解的图。

就是说这三个点就可以随便移动到每个象限,而如果移动完了以后就可以直接对于剩下的点,在三个点中选出不共线的两点进行移动。
难点在于如何将任意三个点移动到第一象限,由于坐标范围很小,不难发现这个过程可以通过搜索完成,初始状态即为开始三个点的坐标,终止状态的话就是三个点的横纵坐标全部大于等于某个值,这个值最好不要太大,可能超时,也不要太小,因为太小可能构成的平行四边形的点仍然不在第一象限,所以我选择了 ,经实测,至少给到 。
Code
C//# pragma GCC optimize("Ofast")
# include <bits/stdc++.h>
# define fr front
# define il inline
# define fir first
# define sec second
# define vec vector
# define it iterator
# define pb push_back
# define lb lower_bound
# define ub upper_bound
# define all(x) x.begin(), x.end()
# define mem(a, b) memset(a, b, sizeof(a))
# define lc (t[p].l)
# define rc (t[p].r)
# define ls(x) (x << 1)
# define rs(x) (x << 1 | 1)
# define lson ls(p), l, mid
# define rson rs(p), mid + 1, r
# define sqr(x) ((x) * (x))
# define bpc __builtin_popcount
# define lowbit(x) ((x) & (-(x)))
# define geti(x, i) (((x) >> (i)) & 1)
# define set1(x, i) ((x) | (1 << (i)))
# define set0(x, i) ((x) & (~(1 << (i))))
# define debug1(x) cerr << #x << " = " << x << " "
# define debug2(x) cerr << #x << " = " << x << "\n"
# define bug cerr << "--------------------------\n"
# define each1(i, x) for(auto (i) : (x))
# define each2(i, x) for(auto (&i) : (x))
# define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
# define pre(i, a, b) for(int i = (a); i >= (b); -- i)
# define G(i, h, u, ne) for(int i = (h[(u)]); i; i = (ne[(i)]))
# define reps(i, a, b, c) for(int i = (a); i <= (b); i += (c))
# define pres(i, a, b, c) for(int i = (a); i >= (b); i -= (c))
using namespace std;
using DB = double;
using LL = long long;
using LDB = long double;
using PII = pair<int, int>;
using ULL = unsigned long long;
const int N = 4e2 + 10;
const int INF1 = 0x3f3f3f3f, INF2 = INT_MAX;
const LL INF3 = (LL)1e18, INF4 = 0x3f3f3f3f3f3f3f3f, INF5 = LLONG_MAX;
int n;
int x[N], y[N], id[N];
bool ok = true;
struct node{
int x[4], y[4];
bool operator < (const node &b) const{
if(x[1] ^ b.x[1]){
return x[1] < b.x[1];
}
if(x[2] ^ b.x[2]){
return x[2] < b.x[2];
}
if(x[3] ^ b.x[3]){
return x[3] < b.x[3];
}
if(y[1] ^ b.y[1]){
return y[1] < b.y[1];
}
if(y[2] ^ b.y[2]){
return y[2] < b.y[2];
}
return y[3] < b.y[3];
}
}emp;
map<node, pair<node, int>> from;
struct result{
int a, b, c;
};
vec<result> f;
node BFS(){
queue<node> q;
node start;
start.x[1] = x[1], start.y[1] = y[1];
start.x[2] = x[2], start.y[2] = y[2];
start.x[3] = x[3], start.y[3] = y[3];
q.push(start);
from[start] = {emp, -1};
while(!q.empty()){
node s = q.fr();
q.pop();
if(max({s.x[1], s.x[2], s.x[3]}) < -10) continue;
if(max({s.y[1], s.y[2], s.y[3]}) < -10) continue;
if(min({s.x[1], s.x[2], s.x[3]}) >= 5 && min({s.y[1], s.y[2], s.y[3]}) >= 5){
node res = s;
while(1){
int i = from[s].sec;
if(i == -1) break;
f.pb({i % 3 + 1, (i + 1) % 3 + 1, i});//另外两个
s = from[s].fir;
}
return res;
}
rep(i, 1, 3){
node now = s;
now.x[i] = (s.x[1] + s.x[2] + s.x[3]) - 2 * s.x[i];//根据中点坐标公式得出来的,推一下就好了
now.y[i] = (s.y[1] + s.y[2] + s.y[3]) - 2 * s.y[i];
if(!from.count(now)){
from[now] = {s, i};
q.push(now);
}
}
}
}
bool check(PII a, PII b, PII c){//叉积判是否在一条直线
return (LL)a.fir * (b.sec - c.sec) + (LL)b.fir * (c.sec - a.sec) + (LL)c.fir * (a.sec - b.sec) == 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
rep(i, 1, n){
cin >> x[i] >> y[i];
id[i] = i;
if(x[i] < 0 || y[i] < 0) ok = false;
}
if(ok){
cout << "0";
return 0;
}
rep(i, 3, n){
if(!check({x[1], y[1]}, {x[2], y[2]}, {x[i], y[i]})){//不共线才能搜
swap(id[3], id[i]);
swap(x[3], x[i]);
swap(y[3], y[i]);
ok = true;
break;
}
}
if(!ok){
cout << "-1\n";
return 0;
}
node s = BFS();
reverse(all(f));
rep(i, 4, n){
if(x[i] >= 0 && y[i] >= 0) continue;
if(!check({s.x[1], s.y[1]}, {s.x[2], s.y[2]}, {x[i], y[i]})) f.pb({1, 2, i});//检查共线情况
else f.pb({1, 3, i});
}
cout << f.size() << "\n";
each2(tmp, f){
cout << id[tmp.a] << " " << id[tmp.b] << " " << id[tmp.c] << "\n";
}
return 0;
}
我想要天天說,天天說,天天對你說,我有多愛你…………
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...