看题集页面写着欧拉定理,我还去查了一下欧拉定理,结果也没看懂。
然后看了题解,发现核心思想就是:“每增加一条直线,对平面区域个数增加的贡献值,是其与先前直线的交点数(不包括与已有交点重合的点)+1 (1相当于加了一条不重复直线就会增加一个区域)”。
我们在遍历一条新的直线时,首先判断这条直线是否和之前的直线是重复的,如果重复的,则没有计算的必要。在这一步中去重的功能通过set来实现。
如果这条直线是不重复的,那么我们首先可以把原有的区域数+1,因为一条直线无论在平面上如何摆放,它的出现就会对平面起到一次切割作用。
然后,这条直线可能还与以前的直线有交点,那么每个不重复交点的存在又会催生一次切割,生成一个新的区域。所以思路就出来了。
代码如下:
devc++不能用auto,写的我很苦恼,太久没写了,还得去查set怎么迭代。😔
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<cmath>
#include<vector>
#include<set>
#define ll long long
using namespace std;
const int N = 2005;
const int mod = 20201114;
int compute(int k, int b, set<pair<int, int> >& s){
set<pair<double, double> >d;
for(set<pair<int, int> >::iterator l = s.begin(); l != s.end(); l++){
int x = l->first;
int y = l->second;
if(x != k){
int kk = k - x;
int bb = y - b;
double xx = (double)bb / kk; //注意不要写反了
double yy = (double)k * xx + b;
// cout<<xx<<" "<<yy<<endl;
d.insert(make_pair(xx, yy)); //交点去重
}
}
return d.size();
}
int main(){
int n;
scanf("%d", &n);
int res = 1; //注意,从1开始,本来就有一个大区域就是平面本身了
set<pair<int, int> >s;
for(int i = 0; i < n; i++){
int k, b;
scanf("%d%d", &k, &b);
int m = s.size();
s.insert(make_pair(k, b));
if(s.size() != m){
res++; //存在即+1
res += compute(k, b, s); //交点贡献的新区域
// cout<<res<<endl;
}
}
cout<<res<<endl;
return 0;
}
到此为止。
借鉴的题解:
昨晚梦见稀里糊涂地去面试,结果是不小心把我勾上的。我死乞白赖地说给我一次机会,结果还是y总面试我。
他说你给我上一门课吧,我说我又不是师范生,我哪会上课?
他说那你给我讲讲质数筛吧,我啊吧啊吧,他说你滚吧!
所以,我还是去买一下y总的每日一题吧!