1. 程式人生 > >Codeforces:"North-East"

Codeforces:"North-East"

nor font sort pan pos ace ons lower insert

Codeforces:"North-East"

題目鏈接:http://codeforces.com/gym/101246/problem/H

題目大意:空間內有$n$個點,現取$x$和$y$嚴格遞增的點組成最長序列,問可能取到哪些點,一定取到哪些點.

DP

這道題要求的是二維LIS,可以按$x$遞增排序將其降為一維,當橫坐標相等時,因為要求坐標嚴格遞增,按$y$遞減排序。

從後面往前搞,$maxy[len]$記錄LIS長度為$len$的點的最大$y$,若以當前點為結尾的LIS長度為$len$,當前點的$y$小於$maxy[len+1]$則為可能取到的點。

代碼如下:

 1 #include <cstdio>
 2
#include <algorithm> 3 #include <vector> 4 #include <set> 5 #define N 100005 6 using namespace std; 7 struct node{ 8 int x,y,id; 9 friend bool operator<(node a,node b){ 10 if(a.x==b.x)return a.y>b.y; 11 return a.x<b.x; 12 } 13 }a[N];
14 const int inf=1000005; 15 int n,dp[N],val[N],k,pos[N],maxy[N]; 16 vector<int>v[N]; 17 set<int>A,B; 18 void init(){ 19 freopen("input.txt","r",stdin); 20 freopen("output.txt","w",stdout); 21 } 22 bool cmp(int x,int y){ 23 return val[x]>val[y]; 24 } 25 void output(){
26 printf("%d",A.size()); 27 for(set<int>::iterator it=A.begin();it!=A.end();++it) 28 printf(" %d",*it); 29 printf("\n"); 30 printf("%d",B.size()); 31 for(set<int>::iterator it=B.begin();it!=B.end();++it) 32 printf(" %d",*it); 33 printf("\n"); 34 } 35 int main(void){ 36 init(); 37 scanf("%d",&n); 38 for(int i=0;i<n;++i){ 39 scanf("%d%d",&a[i].x,&a[i].y); 40 a[i].id=i+1; 41 } 42 sort(a,a+n); 43 for(int i=0;i<n;++i){ 44 int v=a[i].y; 45 int t=lower_bound(dp,dp+k,v)-dp; 46 dp[t]=v; 47 val[a[i].id]=a[i].y; 48 pos[a[i].id]=t; 49 if(t==k)k++; 50 } 51 for(int i=0;i<k;++i) 52 maxy[i]=-inf; 53 maxy[k]=inf; 54 for(int i=n-1;i>=0;--i){ 55 int id=a[i].id; 56 int p=pos[id]; 57 if(val[id]<maxy[p+1]){ 58 A.insert(id); 59 maxy[p]=max(maxy[p],val[id]); 60 v[p].push_back(id); 61 } 62 } 63 for(int i=0;i<k;++i) 64 if((int)v[i].size()==1) 65 B.insert(v[i][0]); 66 output(); 67 }

Codeforces:"North-East"