給定\(n\)行\(m\)列的01矩陣,刪去若干行,使得結果矩陣知足任意相鄰的兩行存在某一列都是1c++
要求輸出刪去的方案優化
比較明顯的能夠列出dp方程 \(dp_i\)表示以\(i\)爲結尾的行的最多行數ui
\(dp[i] =1 + max\{dp[j]\},ij有共同1\)spa
這樣難點就成爲了難以判斷\(ij\)是否有共同的1code
因而能夠考慮get
這樣實際上\(dp\)的含義就變掉了,至關於維護了前\(i\)行的maxit
\(C_i\)表示第\(i\)行有1的列class
區間個數是\(m\)級別,所以\(dp\)的過程最多進行\(O(m)\)次區間詢問和更新date
這題的另外一個難點是方案,這是比較套路的,能夠在線段樹上維護更新來的行數和path路徑用於回溯grid
#include<bits/stdc++.h> #define pii pair<ll,ll> #define fi first #define se second #define equals(a,b) (fabs(a-b) < 1e-8) using namespace std; typedef long long ll; inline ll rd(){ ll x = 0; char ch = getchar(); while(ch < '0' || ch > '9'){ ch = getchar(); } while(ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar(); } return x; } struct SegmentTree{ vector<pii> v; vector<int> tag; SegmentTree(int n):v((n + 1) << 2),tag((n + 1 )<< 2){} inline void push_up(int i){ v[i] = max(v[i << 1],v[i << 1|1]); } inline void update(int i,pii val){ tag[i] = 1; v[i] = val; } inline void push(int i){ if(tag[i]) { update(i << 1,v[i]); update(i << 1|1,v[i]); tag[i] = 0; } } void build(int i,int l,int r){ v[i] = make_pair(0,-1); if(l == r)return; int mid = l + r >> 1; build(i << 1,l,mid); build(i << 1|1,mid + 1,r); push_up(i); } pii query(int i,int l,int r,int L,int R){ if(l > R || r < L) return make_pair(0,-1); if(l >= L && r <= R) return v[i]; push(i); int mid = l + r >> 1; return max(query(i << 1,l,mid,L,R),query(i << 1|1,mid + 1,r,L,R)); } void update(int i,int l,int r,int L,int R,pii val){ if(l > R || r < L) return; if(l >= L && r <= R) return update(i,val); int mid = l + r >> 1; update(i << 1,l,mid,L,R,val); update(i << 1|1,mid + 1,r,L,R,val); push_up(i); } }; inline int get(int x,vector<int>&v){ return lower_bound(v.begin(),v.end(),x) - v.begin() + 1; } int main(){ int n = rd(); int m = rd(); vector<int> vis(n + 1); vector<vector<pii>> lin(n + 1); vector<int> vvv; vector<int> path(n + 1); for(int i = 1;i <= m;i++){ int R = rd(); int l = rd(); int r = rd(); lin[R].push_back(make_pair(l,r)); vvv.push_back(l); vvv.push_back(r); } sort(vvv.begin(),vvv.end()); vvv.erase(unique(vvv.begin(),vvv.end()),vvv.end()); int N = vvv.size(); SegmentTree seg(N); seg.build(1,1,N); for(int i = 1;i <= n;i++){ for(auto &x:lin[i]){ x.fi = get(x.fi,vvv); x.se = get(x.se,vvv); } } for(int i = 1;i <= n;i++){ pii mx = make_pair(0,-1); for(auto it:lin[i]) mx = max(mx,seg.query(1,1,N,it.fi,it.se)); path[i] = mx.se; mx.fi++; mx.se = i; for(auto it:lin[i]) seg.update(1,1,N,it.fi,it.se,mx); } pii mx = seg.query(1,1,N,1,N); int cur = mx.se; int cnt = n; while(cur != -1){ vis[cur] = 1; cnt--; cur = path[cur]; } printf("%d\n",cnt); for(int i = 1;i <= n;i++) if(!vis[i]) printf("%d ",i); }