CodeForces - 1557D Ezzat and Grid(线段树+dp)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 1557D Ezzat and Grid(线段树+dp)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出 n n n 01 01 01 串,现在问最少需要删掉多少个串,才能使得剩下的串拼起来是连通的

规定两个 01 01 01 串是连通的,当且仅当存在至少一列,在两个串中都为 1 1 1

题目分析:正难则反,题目要求删除最少,那么我们思考如何使得保留下来的串最多。考虑 d p [ i ] dp[i] dp[i] 为以第 i i i 个序列为结尾的,可以保留的最多的串的个数,模仿最长不下降子序列的思路, d p [ i ] = d p [ j ] + 1 dp[i]=dp[j]+1 dp[i]=dp[j]+1,当且仅当串 i i i 和串 j j j 是可以连通的,在本题中判断两个串是否连通,可以用线段树判断是否存在区间交即可

其实更简单的,因为我们转移 d p dp dp 时是线性递推的过程,假如对于第 i i i 个串来说,存在区间 [ l , r ] [l,r] [l,r] 都是 1 1 1 的序列,那么不难看出与区间 [ l , r ] [l,r] [l,r] 存在交集的 j j j 串都是可以转移的,但是我们只需要最大值就可以了,所以线段树实际上维护一下区间 [ l , r ] [l,r] [l,r] 内最大的 d p dp dp 值就可以了

需要注意的是区间特别大,所以需要离散化一下,动态开点好像会被卡常,输出答案的时候可以转换为 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;
}

以上是关于CodeForces - 1557D Ezzat and Grid(线段树+dp)的主要内容,如果未能解决你的问题,请参考以下文章

CF 1557D(Ezzat and Grid-线段覆盖)

Codeforces Round #737 (Div. 2) Ezzat and Grid(线段树优化dp)

Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树模拟最长上升子序列

Codeforces Round #737 (Div. 2) D. Ezzat and Grid(线段树,dp)

CF1557D.Ezzat and Grid(2200分线段树)

CF #737(div2)A. Ezzat and Two Subsequences,贪心