最大覆盖问题_前缀长度24是什么意思怎么调

最大覆盖问题_前缀长度24是什么意思怎么调2531最大覆盖现在有nn个位置1…n1…n

最大覆盖问题_前缀长度24是什么意思怎么调"

2531 最大覆盖

 

现在有 nn 个位置 1…n1…n 。

给qq个区间,请你选出选q−2q−2个,使得覆盖位置个数最大。

 收起

输入

第一行两个数n,q(3<=n,q<=5000)。
接下来q行,其中第i行两个数l[i],r[i],表示第i个区间能覆盖所有满足l[i]<=x<=r[i]的位置x。

输出

一个数表示最大值。

输入样例

4 3
1 1
2 2
3 4

输出样例

2

该题目前两种可行思路:

1、正向考虑:选q-2个区间,将所有区间按照区间长度从大到小排序,

每次选择最长的一个区间,选择后将该区间覆盖的区域设定为“无效状态”,

然后更新其他区间的覆盖长度(这里可以前缀和优化,左到单个区间更新O(1)),

重新排序后再选择最长。时间复杂度O(N*NlogN),NlogN是排序时间复杂度。

2、逆向考虑

去掉两个影响最小的:

求出整个区间N上每个 区间内点均-1所产生影响,-2产生的影响(前缀和),

两两枚举题目所给区间,根据是否相交计算影响,选择最小值,作为最终答案。

代码实现(方案2):

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<set>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
const int M=4e5+100;
pair<int,int>arr[N];
int vis[N];
LL pre[5000+10],sum[5000+10];
int main()
{
  int n,q;
  LL ans=0,mini;
  while(cin>>n>>q)
  {
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    memset(sum,0,sizeof(sum));
    ans=0;
    mini=INF;
    for(int i=1; i<=q; i++)
    {
      cin>>arr[i].first>>arr[i].second;
      for(int j=arr[i].first; j<=arr[i].second; j++)
      {
        if(!vis[j])ans++;
        vis[j]++;
      }
    }
    for(int i=1; i<=n; i++)
    {
      pre[i]=pre[i-1]+(int(vis[i]-1>0)^1);
      sum[i]=sum[i-1]+(int(vis[i]-2>0)^1);
    }

    for(int i=1; i<=q; i++)
    {
      for(int j=i+1; j<=q; j++)
      {
        int l1=arr[i].first,l2=arr[j].first;
		int r1=arr[i].second,r2=arr[j].second;
        if(max(l1,l2)<=min(r1,r2))
        {
          mini=min(mini,pre[r1]-pre[l1-1]+pre[r2]-
		  		pre[l2-1]+sum[min(r1,r2)]-sum[max(l1,l2)-1]);
        }
        else
        {
          mini=min(mini,pre[r2]-pre[l2-1]+pre[r1]-pre[l1-1]);
        }
      }
    }
    cout<<ans-mini<<endl;
  }
  return 0;
}

方案一(别人代码):

#include<iostream>
#include<algorithm>

using namespace std;

struct Node {
	int l,r,cs;
} p[10000];

int vis[10000],b[100000];

bool cmp(Node x,Node y) {
	return x.cs>y.cs;
}

int main() {
	int n,q;
	cin>>n>>q;
	for(int i=0; i<q; i++) {
		cin>>p[i].l>>p[i].r;

	}
	for(int i=0; i<=n; i++) {
		vis[i]=1;
	}
	int ans=0;
	for(int i=0; i<q-2; i++) {
		b[0]=vis[0];
		for(int k=1; k <= n; k++)
			b[k]=b[k-1]+vis[k];
		for(int k =0 ; k < q; k++) {
			p[k].cs=b[p[k].r] - b[p[k].l-1];
		}
		sort(p,p+q,cmp);
		for(int k=p[0].l; k<=p[0].r; k++)
			if(vis[k]) {
				ans++;
				vis[k]=0;
			}
	}
	cout<<ans<<endl;
	return 0;
}

THE END

今天的文章最大覆盖问题_前缀长度24是什么意思怎么调分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86809.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注