Codeforces Round 906 (Div. 2) E1

时隔了不知道多久的补题。两个月吧,这是可是寒假的比赛。

但是补题的时候还是遇到了很多问题。
很重要的有一些地方能够简化,一些条件没有充分的利用上,导致了我很多地方考虑的太复杂。
这些能够简化的地方全部利用上我觉得才算是写出来了这道题目,否则这题会复杂到我赛时写不完,而且特别长,很容易就调不出来的程度。
这题的话,则是对使用次数少的时候的可供选择的区间的特殊性不够敏感,事实上只被覆盖过一次的区间是非常特殊的。

这个问题很明显是分为两种情况的,一种是我选择的两个区间是互不相交的,一种是他们之间有相交的区间。 很明显除了这两个没有其他情况。

我当时的第一个想法就是找到前两个分别删去后能够产生的价值最大的区间,然后删掉他们,这就是答案。
然后,离谱的事情来了。
假如这两个区间相交,那他们产生的价值不就是不合法的吗,这样就是错的,所以要符合我们预设的要求,我们应该去对每个点维护只覆盖了这个点之前的位置和之后的位置的区间假如被删去一个所能产生的最大的价值,这样才是符合我们的要求的。
代码复杂程度++。
但是,真的有必要吗?
假如这是对的,那我们的第二个类型的答案要如何维护?
枚举每个区间对,然后尝试删除?
直接T掉,\(O(n^2)\)想都不用想。
然后我顺着这个思路往下,尝试区间排序然后找相邻区间,很高兴的发现这个没有正确性。
而正解就是用一个set来维护,统计当前这个位置已经被覆盖了几次。
假如这个位置被覆盖了两次,那就尝试删去这两个区间,统计答案。
假如只覆盖了一次,是没有必要的。因为这个位置如果是答案,那就有两种答案,一种是覆盖这个位置的区间会再和至少两个区间重合
这种情况下这个区间所覆盖的所有区域可能都不会出现只被覆盖两次的情况,也就是不会去尝试删去这个区间。但是,这个其实已经被考虑过了,就在我们最上面的第一个尝试中。但是如果是完全按照上面所说的第一个情况,也就是排除了选择的两个区间相交的情况,那就不可做了。
考虑这样的三个区间:[1,10],[5,6],[5,6]
这是一个很好的反例,没有任何一个位置被覆盖了三次,但是答案就是删去[1,10]。这个答案是在第一种情况中需要被统计的。
所以我们统计答案的答案,其实是应该分为这样两种:1.这个区间中没有被覆盖两次的位置,2.这个区间中有被覆盖两次的位置。
这才是最简单的统计。

这个思路的产生可以来自简化第一种答案的统计。但是其实有点不现实,写题的思路来自计算当前情况的答案较为简单的方法。。
计算这个答案简单,总体写起来就简单吗?这个贪心可不成立。
还是都试试,都想一下再选择。

主要就是不知道怎么选。很容易钻牛角尖,进了这思路,出不来了。
但是很多时候就是要退出来想想的。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
ll n,m,k;
ll l[200010],r[200010],An[200010];
ll a[200010];
ll sum[200010][5];
vector<ll> seg[200010];
int main()
{
	ll T=read();
	while(T--)
	{
		n=read(),m=read(),k=read();
		for(ll i=1;i<=n;i++)seg[i].clear(),a[i]=0;
		for(ll i=1;i<=m;i++)
		{
			l[i]=read(),r[i]=read();
			a[l[i]]++;a[r[i]+1]--;
			seg[l[i]].push_back(i);
			seg[r[i]+1].push_back(-i);
		}
		ll ans=0;
		for(ll i=1;i<=n;i++)
		{
			sum[i][0]=sum[i-1][0]+a[i];
			if(sum[i][0]==1)sum[i][1]=1;
			else sum[i][1]=0;
			if(sum[i][0]==0)ans++;
			if(sum[i][0]==2)sum[i][2]=1;
			else sum[i][2]=0;
		}
		for(ll i=1;i<=n;i++)
		{
			sum[i][3]=sum[i-1][3]+sum[i][1];
			sum[i][4]=sum[i-1][4]+sum[i][2];
		}
		ll Max1=0,Max2=0;
		for(ll i=1;i<=m;i++)
		{
			An[i]=sum[r[i]][3]-sum[l[i]-1][3];
			if(An[i]>=Max1)
			{
				Max2=Max1;
				Max1=An[i];
			}
			else
			if(An[i]>Max2)Max2=An[i];
		}
		ll Mans=Max1+Max2;
//		cout<<Mans<<endl;
		set<ll> s;
		for(ll i=1;i<=n;i++)
		{
			for(ll j=0;j<seg[i].size();j++)
			{
				if(seg[i][j]<0)s.erase((-seg[i][j]));
				else s.insert((seg[i][j]));
			}
//			cout<<s.size()<<' ';
			if(s.size()==2)
			{
				ll fir=*s.begin(),sec=*s.rbegin();
				ll L=min(l[fir],l[sec]),MidL=max(l[fir],l[sec]),MidR=min(r[fir],r[sec]),R=max(r[fir],r[sec]);
				Mans=max(Mans,sum[MidL-1][3]-sum[L-1][3]+sum[R][3]-sum[MidR][3]+sum[MidR][4]-sum[MidL-1][4]);/*
				if(i==8)
				{
					cout<<L<<' '<<MidL<<' '<<MidR<<' '<<R;
					cout<<endl<<sum[MidL-1][3]-sum[L-1][3]<<' '<<sum[R][3]-sum[MidR][3]<<' '<<sum[MidR][4]-sum[MidL-1][4]<<endl;
				}*/
			}
		}
//		cout<<endl;
		cout<<Mans+ans<<endl;
	}
	return 0;
}
posted @ 2024-04-24 19:51  HL_ZZP  阅读(3)  评论(0编辑  收藏  举报