P7149 [USACO20DEC] Rectangular Pasture S
题目描述
Farmer John 最大的牧草地可以被看作是一个由方格组成的巨大的二维方阵(想象一个巨大的棋盘)。现在,有 NNN 头奶牛正占据某些方格(1≤N≤25001≤N≤25001≤N≤2500)。
Farmer John 想要建造一个可以包围一块矩形区域的栅栏;这个矩形必须四边与 xxx 轴和 yyy 轴平行,最少包含一个方格。请帮助他求出他可以包围在这样的区域内的不同的奶牛子集的数量。注意空集应当被计算为答案之一。
输入格式
输入的第一行包含一个整数 NNN。以下 NNN 行每行包含两个空格分隔的整数,表示一头奶牛所在方格的坐标 (x,y)(x,y)(x,y)。所有 xxx 坐标各不相同,所有 yyy 坐标各不相同。所有 xxx 与 yyy 的值均在 0...1090...10^90...109 范围内。
输出格式
输出 FJ 可以包围的奶牛的子集数量。可以证明这个数量可以用 64 位有符号整数型存储(例如 C/C++ 中的long long)。
输入输出样例 #1
输入 #1
4
0 2
1 0
2 3
3 5
输出 #1
13
说明/提示
共有 242^424 个子集。FJ 不能建造一个栅栏仅包围奶牛 111、222、444,或仅包围奶牛 222、444,或仅包围奶牛 111、444,所以答案为 24−3=16−3=132^4-3=16-3=1324−3=16−3=13。
- 测试点 2-3 满足 N≤20N≤20N≤20。
- 测试点 4-6 满足 N≤100N≤100N≤100。
- 测试点 7-12 满足 N≤500N≤500N≤500。
- 测试点 13-20 没有额外限制。
供题:Benjamin Qi
题目大意:
现在给定N头牛,N头牛分别在横坐标和纵坐标不同的坐标上,求解用一个矩形区域包含不同牛的子集的数量
思路:
这种题一般就是排序后层层分析,首先按照行来进行排序,排序后依次进行行考虑,现在假设到第i行,其中下面还有j行,是必须要包含着两个点的,之后分情况讨论:(第i个方格是一定在第j个方格的上面的)
1、第i个在第j个方格的左边
i
j
形如这样,可以发现方格只可以在i到j之间i的左边添加,j的右边添加,要不然的话不能包含i和j
2、第i个在第j个方格的右边
i
j
形如这样,可以发现方格只可以在i到j之间i的右边添加,j的左边添加,与上述相反
这样情况就分类完了,就可以写代码了
代码:
cpp
#include<bits/stdc++.h>
#define int long long
//#define ull unsigned long long
using namespace std;
//#define x first
//#define y second
//const int mod=1e9+7;
//const int N=1e5+10;
//int fac[N],invfac[N];
//int qmi(int a,int b,int p){int res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
//int inv(int x){return qmi(x,p-2);}
//int C(int n,int m){if(n<0||m<0||n<m)return 0;return fac[n]*invfac[n-m]%p*invfac[m]%p;}
//void init(){fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%p;invfac[N-1]=inv(fac[N-1]);for(int i=N-2;i>=0;i--)invfac[i]=invfac[i+1]*(i+1)%p;}
//struct node{int v,w;bool operator < (const node &x)const{return w==x.w ? v>x.v : w>x.w;}};
//void dijkstra(const vector<vector<node>>&g,vector<int>&dist,vector<bool>&vis,int x){fill(dist.begin(),dist.end(),LLONG_MAX);fill(vis.begin(),vis.end(),false);
//dist[x]=0;priority_queue<node>q;q.push({x,0});while(q.size()){auto u=q.top().v;q.pop();if(vis[u])continue;vis[u]=true;for(auto [v,w]:g[u]){if(dist[v]>dist[u]+w){
//dist[v]=dist[u]+w;q.push({v,dist[v]});}}}}
//struct BIT{int n;vector<int>t;BIT(int _n=0){init(_n);}void init(int _n){n=_n;t.assign(n+2,0);}
//void add(int x,int v){for(;x<=n;x+=(x & -x))t[x]+=v;}int query(int x){int res=0;for(;x;x-=(x & -x))res+=t[x];return res;}};
//int calc_add(const vector<vector<int>>&s,int x1,int y1,int x2,int y2){return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];}
//void calc_diff(vector<vector<int>>&d,int x1,int y1,int x2,int y2,int c){d[x1][y1]+=c;d[x2+1][y1]-=c;d[x1][y2+1]-=c;d[x2+1][y2+1]+=c;}
//int primes[N],cnt=0;bool st[N];
//void init1(){for(int i=2;i<N;i++){if(!st[i])primes[++cnt]=i;for(int j=1;primes[j]*i<N;j++){st[primes[j]*i]=true;if(i%primes[j]==0)break;}}}
//vector<int>factor[N];void init2(){for(int i=1;i<N;i++){for(int j=i;j<N;j+=i){factor[j].push_back(i);}}}
//int find(vector<int>&pre,int x){return pre[x]=(pre[x]==x ? x : find(pre,pre[x]));}
//void merge(vector<int>&pre,int x,int y){int fx=find(pre,x),fy=find(pre,y);if(fx==fy)return;pre[fx]=fy;}
//bool check(vector<int>&pre,int x,int y){return find(pre,x)==find(pre,y);}
//string add(string x,string y){if((int)x.size()<(int)y.size())swap(x,y);int n=x.size();int m=y.size();reverse(x.begin(),x.end());reverse(y.begin(),y.end());
//int d=0;string ans;for(int i=0;i<n;i++){int x1=(x[i]-'0');int y1=(i<m ? y[i]-'0' : 0);int sum=x1+y1+d;ans.push_back((sum%10)+'0');d=sum/10;}
//if(d>0)ans.push_back(d+'0');reverse(ans.begin(),ans.end());return ans;}
//string mul(string x,string y){if(x=="0"||y=="0")return "0";reverse(x.begin(),x.end());reverse(y.begin(),y.end());int x1=x.size();int y1=y.size();string ans;
//for(int i=0;i<x1;i++){int d=0;int val1=(x[i]-'0');for(int j=0;j<y1;j++){int val2=(y[j]-'0');int len=ans.size();int val=val1*val2+d;
//if(len<=i+j)ans.push_back((val%10)+'0');else val+=(ans[i+j]-'0'),ans[i+j]=((val%10)+'0');d=val/10;}int len=ans.size();int cur_pos=i+y1;
//while(d){if(cur_pos>=len)ans.push_back((d%10)+'0');else d+=ans[cur_pos]-'0',ans[cur_pos]=((d%10)+'0');d/=10;cur_pos++;}}reverse(ans.begin(),ans.end());return ans;}
//struct Seg_Tree{int n;vector<int>t,lz;Seg_Tree(int _n=0){init(_n);}void init(int _n){n=_n;t.assign((n<<2)+2,0);lz.assign((n<<2)+2,0);}
//void pushup(int o){t[o]=t[o<<1]+t[o<<1|1];}void update(int s,int e,int o,int x){t[o]+=x*(e-s+1);lz[o]+=x;}
//void pushdown(int s,int e,int o){if(!lz[o])return ;int mid=(s+e)>>1;update(s,mid,o<<1,lz[o]);update(mid+1,e,o<<1|1,lz[o]);lz[o]=0;}
//void add(int l,int r,int x,int s=1,int e=0,int o=1){if(e==0)e=this->n;if(l>e||r<s)return ;if(l<=s&&e<=r){update(s,e,o,x);return ;}pushdown(s,e,o);int mid=(s+e)>>1;
//add(l,r,x,s,mid,o<<1);add(l,r,x,mid+1,e,o<<1|1);pushup(o);}
//int query(int l,int r,int s=1,int e=0,int o=1){if(e==0)e=this->n;if(l>e||r<s)return 0;if(l<=s&&r>=e)return t[o];pushdown(s,e,o);int mid=(s+e)>>1;
//int x=query(l,r,s,mid,o<<1);int y=query(l,r,mid+1,e,o<<1|1);return x+y;}};
void solve(){
int n;
cin>>n;
vector<pair<int,int>>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i].first>>a[i].second;
sort(a.begin()+1,a.end(),[](const pair<int,int>p1,const pair<int,int>p2){
return p1.second<p2.second;
});
//记录j上边的左边和右边分别有多少个数
//因为j是从上往下的
vector<int>l(n+1),r(n+1);
int ans=1;
for(int i=1;i<=n;i++){
ans++;
int lt=0,rt=0;
for(int j=i-1;j>=1;j--){
if(a[i].first<a[j].first){
ans+=(lt+1)*(r[j]+1);
rt++;
l[j]++;
}
else{
ans+=(rt+1)*(l[j]+1);
lt++;
r[j]++;
}
}
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
//init();
//init1();
//init2();
int _=1;
//cin>>_;
while(_--)solve();
return 0;
}