题目大意:
题目链接:https://www.luogu.org/problem/P3084
一个长度为的序列,给出个二元组,表示中有且仅有一个数字1。求该01序列中最多含有多少个1。
思路:
题型很明显是差分约束。
对于其中一个二元组,我们需要满足的是,所以就变成。
然后显然任意一个数字只能选或不选,所以有,变一下型就可以了。
但是这样会被卡。。。只能拿到60分。
代码链接
我们设表示在位置必放1,前个数字中1最多的个数。
那么既然在位置选择了1,那么所有含有位置的区间都不可以选1。
设。这样的话,都不可以选择1。
但是因为每个区间至少要有一个1,所以不含的区间都必须要有1。
设,那么在的右区间内必然会至少有一个1。
所以位置的上一个1的区间范围就是。
由于要求最大,就用单调队列维护一下就可以了。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200010;
int n,m,f[N],l[N],r[N];
deque<int> q;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n+1;i++)
r[i]=i-1;
for (int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
l[y+1]=max(l[y+1],x);
r[y]=min(r[y],x-1);
}
for (int i=2;i<=n+1;i++)
l[i]=max(l[i-1],l[i]);
for (int i=n;i>=1;i--)
r[i]=min(r[i],r[i+1]);
int j=1;
q.push_back(0);
for (int i=1;i<=n+1;i++)
{
while (q.size()&&q.front()<l[i]) q.pop_front();
for (;j<=r[i]&&j<=n+1;j++)
{
if (j<l[i] || f[j]<0) continue;
while (q.size()&&f[q.back()]<f[j]) q.pop_back();
q.push_back(j);
}
if (q.size()) f[i]=f[q.front()]+1;
else f[i]=-1;
}
if (f[n+1]>0) printf("%d
",f[n+1]-1);
else printf("-1");
return 0;
}