题目大意
给你 n n n 条线段, A l i c e Alice Alice 每次从中选 k k k 条, B o b Bob Bob 每次划一条直线,定义 p e n a l t y penalty penalty 为 B o b Bob Bob 所划直线与 A l i c e Alice Alice 所选直线相交的直线数, A l i c e Alice Alice 想最大化 p e n a l t y penalty penalty, B o b Bob Bob 想最小化 p e n a l t y penalty penalty,对于每一个 1 − n 1-n 1−n 的 k k k,你都需要回答 p e n a l t y penalty penalty 的值
解题思路
显然
A
l
i
c
e
Alice
Alice 每次选不平行的直线是最优的,然后选最多平行数量为
2
、
3
、
4
⋯
2、3、4 \cdots
2、3、4⋯ 这样即可。
首先统计平行的直线有多少条,然后计算有多少种组平行数为
2
、
3
、
4
⋯
2、3、4 \cdots
2、3、4⋯ 的直线,用一个桶来记录,最后将这个桶求一个后缀和,然后正向输出就行。
Code
#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
using namespace std;
const int MAXN = 2e5 + 7;
ll v[MAXN], pre[MAXN];
int n;
map<pair<ll, ll>, int> mp;
ll gcd(ll a, ll b){
return b ? gcd(b, a%b) : a;
}
void solve(){
mp.clear();
scanf("%d",&n);
for(int i = 1; i <= n; i++){
ll x1, y1, x2, y2;
scanf("%lld%lld%lld%lld",&x1, &y1, &x2, &y2);
ll xx = x1 - x2, yy = y1 - y2;
if(xx == 0){
mp[{0,1}]++;
}
else if(yy == 0){
mp[{1,0}]++;
}
else{
if(xx < 0){
xx = -xx, yy = -yy;
}
ll g = gcd(xx, abs(yy));
mp[{xx/g, yy/g}]++;
}
}
for(int i = 1; i <= n; i++)
v[i] = pre[i] = 0;
int maxx = -1;
for(auto it : mp){
v[it.se]++;
}
pre[n+1] = 0;
for(int i = n; i >= 1; i--)
pre[i] = pre[i+1] + v[i];
int cnt = 1;
for(int i = 1; i <= n; i++){
if(!pre[cnt]) cnt++;
pre[cnt]--;
printf("%d\n",i-cnt);
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int T;
scanf("%d",&T);
while(T--){
solve();
}
return 0;
}