ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 CF1684F Diverse Segments

2022-08-03 23:02:30  阅读:156  来源: 互联网

标签:le 覆盖 int 题解 Segments CF1684F 端点 区间 sum


vp 的时候写了一个比较愚蠢的做法过了。

首先选择一个区间修改等价于删掉这个区间。那么考虑它给定的 \(m\) 个区间会有什么影响。假设给定的某个区间是 \([l,r]\),那么假设颜色 \(col\) 在这个区间出现 \(k\) 次,下标是 \(c_1,c_2,...,c_k\)。那么:

  • \(0\le k\le 1\):没用。
  • \(k\ge 2\):答案区间必须要覆盖 \(c_2,c_3,...,c_{k-1}\),并且要覆盖 \(c_1\) 和 \(c_k\) 的至少一个。

要是得到了所有 \(c\),我们就得到若干个条件形式是下面两者之间一个:

  1. 必须覆盖 \(x\)。
  2. 必须覆盖 \(x\) 和 \(y\) 之一。

很容易贪心去做。具体地,从小到大枚举答案右端点 \(r\),维护一个堆,每次用 \(r\) 减去堆的最小值更新答案。考虑对于第 \(2\) 类条件,我们在左端点的时候加入,到右端点的时候删除左端点,再加入右端点。

但是得到 \(c\) 需要的复杂度还是不对。记在 \(x\) 后且颜色与 \(x\) 相同的第一个位置为 \(s(x)\)(找不到则为 \(n+1\))。我们考虑把左端点从小到大扫过去,对于位置 \(l\),找到 \(l\) 所在给定区间的最大的 \(r\)。如果 \(s(s(x))\le r\),那么 \(s(x)\) 是一定要覆盖的位置(即条件 \(1\))。再找到 \(r\) 前面第一个和 \(l\) 同颜色的位置 \(p\),那么需要满足必须覆盖 \(l,p\) 之一(即条件 \(2\))。容易发现这样就涵盖了所有条件。

这样就做完了。实现的时候有点细节。

下面是场上写的丑陋代码,并不建议阅读。有疑问可以私信我。

const int N=500005;
int n,m,sum; 
int a[N],s[N],c[N];
int p[N],h[N];
map<int,int>tmp;
int col;
vector<int>b[N];
int g[N];
vector<int>f[N];
void add(int x,int y)
{
	sum++;
	g[x]++;
	f[y].push_back(x);
}
multiset<int>se;
void work()
{
	cin >> n >> m;
	sum=0;
	tmp.clear();
	col=0;
	for (int i=1;i<=n;i++) cin >> a[i];
	for (int i=1;i<=n;i++)
	{
		g[i]=0;
		f[i].clear();
		if (tmp[a[i]]==0) tmp[a[i]]=++col;
		a[i]=tmp[a[i]];
	}
	for (int i=1;i<=n;i++) c[i]=0,p[i]=0;
	for (int i=n;i>=1;i--)
	{
		if (p[a[i]]==0) s[i]=n+1;
		else s[i]=p[a[i]];
		p[a[i]]=i;
	}
	s[n+1]=n+1;
	for (int i=1;i<=n;i++) b[i].clear();
	for (int i=1;i<=m;i++)
	{
		int l,r;
		cin >> l >> r;
		b[l].push_back(r);
	}
	for (int i=1;i<=n;i++) b[i].push_back(i);
	int mx=0;
	for (int i=1;i<=n;i++)
	{
		for (int j:b[i]) mx=max(mx,j);
		int u=s[i],v=s[u];
		if (v<=mx) c[u]=1;
	}
	int l=n+1,r=0;
	for (int i=1;i<=n;i++)
	{
		if (c[i]==1) r=max(r,i),l=min(l,i);
	}
	for (int i=l;i<=r;i++) c[i]=1;
	// cout << l << " " << r << endl << endl;
	mx=0;
	for (int i=1;i<=n;i++) h[i]=0;
	for (int i=1;i<=n;i++)
	{
		for (int j:b[i])
		{
			while (mx<j)
			{
				mx++;
				h[a[mx]]=mx;
			}
		}
		if (c[i]) continue;
		int u=h[a[i]];
		if (i!=u) add(i,u);
	}
	if (sum==0)
	{
		if (r==0) cout << 0 << endl;
		else cout << r-l+1 << endl;
		return;
	}
	if (r!=0) sum+=r-l+1;
	int ans=n,uu=0;
	se.clear();
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=g[i];j++) se.insert(i),uu++;
		if (c[i]) se.insert(i),uu++;
		for (int j:f[i]) 
		{
			se.erase(se.find(j));
			se.insert(i);
		}
		if (uu==sum) ans=min(ans,i-*se.begin()+1);
		//cout << "11c " << *se.begin() << endl;
	}
	cout << ans << endl;
}

标签:le,覆盖,int,题解,Segments,CF1684F,端点,区间,sum
来源: https://www.cnblogs.com/irty/p/16549020.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有