链接:https://www.nowcoder.com/acm/contest/143/I
来源:牛客网
题目描述
Kanade has an infinity set H contain all of sets such as {(x,y)|x>=a,l<=y<=r} (a,l,r are arbitrary real numbers)
A point set S is good if and only if for each subset T of S there exist h in H satisfy
Now kanade has n distinct points and she want to know how many non-empty subset of these points is good.
You need to output the answer module 998244353
输入描述:
The first line has one integer n
Then there are n lines,each line has two integers x,y denote a point (x,y)
输出描述:
Output the answer module 998244353
示例1
输入
复制
3
1 1
2 2
3 3
输出
复制
6
题目大意:题目中定义如果一个点集|S|是好的,那么这个点集内的任意一个子点集|T|都可以被一个右边无限长的矩形所覆盖,但是除了这个子点集以外的点都不会被这个矩形覆盖。现在给你二维平面内的n个点,问你一共有多少个点集是好的。
题目思路:先讨论点集S中只有一个点的情况,很明显任意一个只有一个点的点集都是好的。
再讨论点集S中有两个点的情况,我们可以发现只要两个点的y坐标不同,那么这个点集也是好的。因为如果两个点的y坐标是相同的话,以x坐标较小的点单独作为这个点集的子点集时,无论怎么取矩形,右侧都是会覆盖到x坐标较大的点。
接着讨论点集S中有三个点的情况,通过观察发现只有三个点呈现类似 “<” 的形状的时候才能满足题目的条件,其它情况下,都会有一个子点集用矩形覆盖时会覆盖到其它的点。
继续讨论点集S中有大于三个点的情况,我们发现任意三个点无法都形成 “<”的形状,故大于三个点的点集都不是好的点集。
点集|S|中只有一个点和两个点的情况还是很好处理的,对于有三个点的情况,我们可以通过一个树状数组来进行维护。
我们将所有的点的坐标离散化之后按照x坐标从小到大排序。然后倒着将每一个点按y坐标插入树状数组中,每次找出当前点的左上方有多少个点,右下方有多少个点,即可统计出答案。
具体实现看代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define MP make_pair
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef vector<int> VI;
const int MX=1e5+5;
const int mod=998244353;
const int inf=0x3f3f3f3f;
//head
int n;
struct Point{
int x,y;
ll up,down;
}a[MX];
bool cmp1(Point A,Point B){
if(A.x==B.x) return A.y<B.y;
return A.x<B.x;
}
bool cmp2(Point A,Point B){
if(A.x==B.x) return A.y>B.y;
return A.x<B.x;
}
VI has;
int get_id(int x){
return lower_bound(has.begin(),has.end(),x)-has.begin()+1;
}
ll bit[MX];
void add(int x,ll d){
for(int i=x;i<=n;i+=lowbit(i))
bit[i]+=d;
}
ll sum(int x){
ll res=0;
for(int i=x;i;i-=lowbit(i))
res+=bit[i];
return res;
}
ll num[MX];
int main(){
//FIN;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
has.pb(a[i].y);
}
sort(has.begin(),has.end());
has.erase(unique(has.begin(),has.end()),has.end());
sort(a+1,a+n+1,cmp1);
for(int i=n;i>=1;i--){
int idy=get_id(a[i].y);num[idy]++;
a[i].up=sum(idy-1);
add(idy,1);
}
sort(a+1,a+n+1,cmp2);
clr(bit);
for(int i=n;i>=1;i--){
int idy=get_id(a[i].y);
a[i].down=sum(n)-sum(idy);
add(idy,1);
}
ll ans=(n+(ll)n*(n-1)/2)%mod;
for(int i=1;i<=n;i++){
ans=(ans-num[i]*(num[i]-1)/2+mod)%mod;
ans=(ans+a[i].up*a[i].down)%mod;
}
printf("%lld\n",ans);
return 0;
}