Description
一个点集 S S S是合法的当且仅当对该集合的每个子集 T T T,都存在三元组 ( a , l , r ) (a,l,r) (a,l,r),使得 h ( a , l , r ) ∩ S = T h(a,l,r)\cap S=T h(a,l,r)∩S=T,其中 h ( a , l , r ) = { ( x , y ) ∣ x ≥ a , l ≤ y ≤ r } h(a,l,r)=\{(x,y)|x\ge a,l\le y\le r\} h(a,l,r)={(x,y)∣x≥a,l≤y≤r}
给出 n n n个点组成的点集,找出其合法非空子集个数
Input
第一行一整数 n n n表示点数,之后 n n n行每行输入一个点的横纵坐标 x , y x,y x,y
( 1 ≤ n ≤ 1 0 5 , 1 ≤ x , y ≤ 1 0 9 ) (1\le n\le 10^5,1\le x,y\le 10^9) (1≤n≤105,1≤x,y≤109)
Output
输出所给点集的合法子集个数,结果模 998244353 998244353 998244353
Sample Input
3
1 1
2 2
3 3
Sample Output
6
Solution
1.单点集必然可以,方案数 n n n
2.两个点的点集,若两点纵坐标相同则不行,其他情况都可以,统计纵坐标为 i i i出现的次数 n u m i num_i numi,那么方案数为 C n 2 − ∑ C n u m i 2 C_n^2-\sum C_{num_i}^2 Cn2−∑Cnumi2
3.三个点的点集,三点纵坐标均不能相同,且有一点横坐标需要严格小于另外两点横坐标,假设三点坐标为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1,y1),(x2,y2),(x3,y3),那么有 x 1 < x 2 , x 3 , y 2 < y 1 < y 3 x_1<x_2,x_3,y_2<y_1<y_3 x1<x2,x3,y2<y1<y3,考虑 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)对答案的贡献,即为所有横坐标大于 x 1 x_1 x1,纵坐标大于 y 1 y_1 y1的点的个数乘上横坐标大于 x 1 x_1 x1,纵坐标小于 y 1 y_1 y1的点的个数,将所有点按横坐标从大到小排序,将纵坐标插入树状数组中计数即可
4.超过三个点的点集无解
Code
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 100005
struct BIT
{
#define lowbit(x) (x&(-x))
int b[maxn],n;
void init(int _n)
{
n=_n;
for(int i=1;i<=n;i++)b[i]=0;
}
void update(int x,int v)
{
while(x<=n)
{
b[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
}bit;
P a[maxn];
int n,h[maxn],num[maxn];
#define x first
#define y second
#define mod 998244353
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
h[i-1]=a[i].y;
}
sort(h,h+n);
int m=unique(h,h+n)-h;
for(int i=1;i<=n;i++)
{
a[i].y=lower_bound(h,h+m,a[i].y)-h+1;
num[a[i].y]++;
}
bit.init(m);
sort(a+1,a+n+1);
ll ans=n+1ll*n*(n-1)/2;
for(int i=1;i<=m;i++)ans-=1ll*num[i]*(num[i]-1)/2;
for(int i=n;i>=1;i--)
{
int j=i;
while(j>=1&&a[j].x==a[i].x)j--;
j++;
for(int k=j;k<=i;k++)
ans+=1ll*(bit.query(m)-bit.query(a[k].y))*bit.query(a[k].y-1);
for(int k=j;k<=i;k++)bit.update(a[k].y,1);
i=j;
}
printf("%lld\n",ans%mod);
return 0;
}