CF2096D题解
CF2096D 题解
题意忘了就点进 CF 里面看,总之就是非常人类智慧。
分析
没有任何头绪,甚至搜索都没办法写。就像求积分一样,你可以很轻松地从 \(A\) 到 \(B\),但是从 \(B\) 到 \(A\) 却是一个非常 NP 的过程,这种问题通常都是无从下手的,也只能说做一道积累一道的经验。
这种异或门开关无非就是涉及到奇偶性,考虑一开始的图只有一个点,也就是我们要求的点 \((s,t)\),那么整个坐标系的所有竖直直线中,只有 \(x=s\) 这一条上面有奇数个点。这时如果我们对任意位置进行操作,这个性质会改变吗?分类讨论一下发现是不会的,所以这个横坐标 \(s\) 和点的奇偶个数就变成了一个充要关系。我们在读入的时候用 map 记录每个坐标上面的点的个数,最后遍历一下这个 map,发现奇数个的时候,说明这时一定有 \(x=s\)。
那如何确定 \(t\)?发现如果延用上述思路去对 \(y\) 坐标对应直线上点的个数进行讨论,就没有这样的“充要性质”了。为什么呢?回到确定 \(s\) 的时候的方法的本质,其实是我们每次操作对于 \(x=c\) 的直线都只会引入偶数个点,但是对于 \(y=c\) 就不再有这样的性质了。没关系,换个角度看,就又有这个性质了————从 \(y=-x+c\) 的方向看,每次操作同样只会引入偶数个点。于是我们对 \(x+y\) 的值如法炮制,就能够求出 \(s+t\) 了。
从而,我们分别得到了 \(s,t\) 的值。
Code
#include<bits/stdc++.h>
using namespace std;
map<int,int> cor,cor1;
inline void solve()
{
cor.clear(),cor1.clear();
int n;
cin>>n;
int x,y;
for(int i=1;i<=n;++i)
{
cin>>x>>y;
cor[x]++;
cor1[x+y]++;
}
int s,t;
for(auto it:cor)
{
if(it.second&1)
{
s=it.first;
break;
}
}
for(auto it:cor1)
{
if(it.second&1)
{
t=it.first-s;
break;
}
}
cout<<s<<" "<<t<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;cin>>T;
while(T--)solve();
return 0;
}
为什么要练,为什么要写?
引用一句让我幡然悔悟的话:
“练了不一定写的出来正解,不练一定写不出来正解”
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/18848970

浙公网安备 33010602011771号