티스토리 뷰
이 문제의 해결 방법에 대한 아이디어 및 코드 출처(koosaga님), 설명은
2020/01/24 - [분류 전체보기] - dp와 분할정복으로 LIS 해결
에서 충분히 하였다.
본 문제를 다시 설명하면
$m=2$일 때는 첫 째 행에 대해 정렬시켰을 때 두 번째 행에 대한 lis를 구하는 문제이므로 간단하다.
$m=3$일 때가 중요한데...
마찬가지로 같은 아이디어를 적용하면 첫 째 행에 대해 정렬시켰을 때 pair에 대한 lis를 구하는 문제로 바뀐다.
그리고 이 문제에 대한 핵심 아이디어 dp와 divide&conquer 풀이법은 이전글에서 설명하였다.
항이 하나 늘어나기는 했으나 핵심은 같다.
단, 원소의 범위가 $1$~$10^9$ 이므로 좌표 압축을 해야 한다.
따라서 코드로 설명을 대체한다.
#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<stack>
#include<map>
#include<queue>
#include<utility>
#include<string>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<cmath>
#include<time.h>
using namespace std;
/*koosaga님의 풀이를 보고 공부했음
아이디어: https://codeforces.com/blog/entry/43319
의 koosaga님의 댓글
*/
typedef pair<int,int> P;
int m,n;
/*dp[i]: i번째 pair까지 써서 만들 수 있는 lis 길이*/
int dp[200010];
/*BIT*/
int fen[200010];
vector<P> v;
struct S{
int xx,yy,z;
bool operator< (const S &tmp)const{
return xx<tmp.xx;
}
};
void add(int pos,int val){
pos++;
while(pos<200010){
fen[pos]=max(fen[pos],val);
pos+=(pos&-pos);
}
}
void erase(int pos){
pos++;
while(pos<200010){
fen[pos]=0;
pos+=(pos&-pos);
}
}
int query(int pos){
int ret=0;
pos++;
while(pos>0){
ret=max(ret,fen[pos]);
pos-=(pos&-pos);
}
return ret;
}
//분할 정복
void solve(int s,int e){
if(s==e) {dp[s]++;return;}
int mid=(s+e)/2;
solve(s,mid);
vector<S> l,r;
for(int i=s;i<=mid;i++) l.push_back((S){v[i].first,v[i].second,dp[i]});
for(int i=mid+1;i<=e;i++) r.push_back((S){v[i].first,v[i].second,i});
sort(l.begin(),l.end());
sort(r.begin(),r.end());
int ptr=0;
int len=l.size();
for(S here:r){
while(ptr<len && l[ptr].xx<here.xx){
add(l[ptr].yy,l[ptr].z);
ptr++;
}
dp[here.z]=max(dp[here.z],query(here.yy-1));
}
for(int i=0;i<ptr;i++) erase(l[i].yy);
solve(mid+1,e);
}
int main(){
cin>>m>>n;
/*이 경우는 첫째 행에 대한 lis구하는 것과 동일하다*/
if(m==2){
vector<P> v1(n);
for(int i=0;i<n;i++) scanf("%d",&v1[i].first);
for(int i=0;i<n;i++) scanf("%d",&v1[i].second);
sort(v1.begin(),v1.end());
//이제 lis 길이를 구하자
vector<int> ans;
for(int i=0;i<n;i++){
if(ans.empty()) ans.push_back(v1[i].second);
else{
vector<int>::iterator it=lower_bound(ans.begin(),ans.end(),v1[i].second);
if(it==ans.end()) ans.push_back(v1[i].second);
else *it=v1[i].second;
}
}
cout<<ans.size();
}
/*이 경우는 첫째 행에 대한 pair에 대한 lis를 구하는 것과 동일하다*/
else{
vector<pair<int,P> > d(n);
for(int i=0;i<n;i++) scanf("%d",&d[i].first);
for(int i=0;i<n;i++) scanf("%d",&(d[i].second).first);
for(int i=0;i<n;i++) scanf("%d",&(d[i].second).second);
sort(d.begin(),d.end());
/*compress*/
vector<int> x,y;
for(int i=0;i<n;i++) x.push_back((d[i].second).first);
for(int i=0;i<n;i++) y.push_back((d[i].second).second);
sort(x.begin(),x.end());
sort(y.begin(),y.end());
for(int i=0;i<n;i++){
int a,b;
a=lower_bound(x.begin(),x.end(),d[i].second.first)-x.begin();
b=lower_bound(y.begin(),y.end(),d[i].second.second)-y.begin();
v.push_back(P(a,b));
}
//이제 pair로 이루어진 v의 lis를 구하면 된다.
solve(0,n-1);
cout<< *max_element(dp,dp+n);
}
return 0;
}
'알고리즘' 카테고리의 다른 글
atcoder dp contest (0) | 2020.04.25 |
---|---|
BOJ 10742 (0) | 2020.02.24 |
dp와 분할정복으로 LIS 해결 (0) | 2020.01.24 |
BOJ 10548 (BOB) (0) | 2020.01.12 |
소가 길을 건너간 이유 11 (0) | 2020.01.08 |
댓글
공지사항