CodeForces - 1557D Ezzat and Grid(线段树+dp)
題目鏈接:點擊查看
題目大意:給出 nnn 個 010101 串,現(xiàn)在問最少需要刪掉多少個串,才能使得剩下的串拼起來是連通的
規(guī)定兩個 010101 串是連通的,當(dāng)且僅當(dāng)存在至少一列,在兩個串中都為 111
題目分析:正難則反,題目要求刪除最少,那么我們思考如何使得保留下來的串最多。考慮 dp[i]dp[i]dp[i] 為以第 iii 個序列為結(jié)尾的,可以保留的最多的串的個數(shù),模仿最長不下降子序列的思路,dp[i]=dp[j]+1dp[i]=dp[j]+1dp[i]=dp[j]+1,當(dāng)且僅當(dāng)串 iii 和串 jjj 是可以連通的,在本題中判斷兩個串是否連通,可以用線段樹判斷是否存在區(qū)間交即可
其實更簡單的,因為我們轉(zhuǎn)移 dpdpdp 時是線性遞推的過程,假如對于第 iii 個串來說,存在區(qū)間 [l,r][l,r][l,r] 都是 111 的序列,那么不難看出與區(qū)間 [l,r][l,r][l,r] 存在交集的 jjj 串都是可以轉(zhuǎn)移的,但是我們只需要最大值就可以了,所以線段樹實際上維護一下區(qū)間 [l,r][l,r][l,r] 內(nèi)最大的 dpdpdp 值就可以了
需要注意的是區(qū)間特別大,所以需要離散化一下,動態(tài)開點好像會被卡常,輸出答案的時候可以轉(zhuǎn)換為 dp 的路徑輸出問題
代碼:
// Problem: D. Ezzat and Grid // Contest: Codeforces - Codeforces Round #737 (Div. 2) // URL: https://codeforces.com/contest/1557/problem/D // Memory Limit: 256 MB // Time Limit: 2500 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; vector<pair<int,int>>node[N]; int dp[N],pre[N]; bool ban[N]; struct Node {int l,r,mmax,lazy; }tree[N<<2]; void pushup(int k) {tree[k].mmax=dp[tree[k<<1].mmax]>dp[tree[k<<1|1].mmax]?tree[k<<1].mmax:tree[k<<1|1].mmax; } void pushdown(int k) {if(tree[k].lazy) {int lz=tree[k].lazy;tree[k].lazy=0;tree[k<<1].lazy=tree[k<<1|1].lazy=lz;tree[k<<1].mmax=tree[k<<1|1].mmax=lz;} } void build(int k,int l,int r) {if(l>r) {return;}tree[k]={l,r,0,0};if(l==r) {return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); } void update(int k,int l,int r,int val) {if(tree[k].l>r||tree[k].r<l) {return;}if(tree[k].l>=l&&tree[k].r<=r) {tree[k].mmax=val;tree[k].lazy=val;return;}pushdown(k);update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k); } int query(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l) {return 0;}if(tree[k].l>=l&&tree[k].r<=r) {return tree[k].mmax;}pushdown(k);int ans1=query(k<<1,l,r),ans2=query(k<<1|1,l,r);if(dp[ans1]>dp[ans2]) {return ans1;} else {return ans2;} } vector<int>dis; int get_id(int x) {return lower_bound(dis.begin(),dis.end(),x)-dis.begin()+1; } void discreate() {sort(dis.begin(),dis.end());dis.erase(unique(dis.begin(),dis.end()),dis.end());for(int i=1;i<N;i++) {for(auto &it:node[i]) {it.first=get_id(it.first),it.second=get_id(it.second);}} } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m;read(n),read(m);for(int i=1;i<=m;i++) {int id,l,r;read(id),read(l),read(r);node[id].push_back({l,r});dis.push_back(l),dis.push_back(r);}discreate();build(1,1,dis.size());dp[0]=0,pre[0]=-1;for(int i=1;i<=n;i++) {dp[i]=1,pre[i]=0;for(auto it:node[i]) {int l=it.first,r=it.second;int p=query(1,l,r);if(dp[p]+1>dp[i]) {dp[i]=dp[p]+1;pre[i]=p;}}for(auto it:node[i]) {int l=it.first,r=it.second;update(1,l,r,i);}}int mmax=*max_element(dp+1,dp+1+n);for(int i=1;i<=n;i++) {if(mmax==dp[i]) {int pos=i;while(pos!=-1) {ban[pos]=true;pos=pre[pos];}break;}}vector<int>ans;for(int i=1;i<=n;i++) {if(!ban[i]) {ans.push_back(i);}}cout<<ans.size()<<endl;for(auto it:ans) {cout<<it<<' ';}cout<<endl;return 0; }總結(jié)
以上是生活随笔為你收集整理的CodeForces - 1557D Ezzat and Grid(线段树+dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷 - P4721 【模板】分治 FF
- 下一篇: 洛谷 - P4717 【模板】快速莫比乌