题目大意:有一条线段,上面的点被若干条线段覆盖着. Sasha想知道是否存在一个整点被所有的线段覆盖,她每次可以任选一个点,Teodor会告诉她这个点被多少个线段覆盖,但是Sasha不知道有多少条线段.求Sasha最多猜多少次还不知道这个问题的答案. 也就是说,如果你最多猜n次能知道答案,那么输出n-1.如果猜不到答案就输出n.
分析:这种题目把图一画,各种情况考虑一下就能做出来了.
什么情况下Sasha能知道答案呢? 在这幅图中,1,2,3都被猜过了,覆盖2的线段数小于覆盖1,3的,而线段是连续的,说明有线段到2这个点就中断了,自然就没有整点被所有的线段给覆盖了. 同样的,如果覆盖2的线段数大于覆盖1,3的,也是能够猜出来的. 为了使猜的次数最多,把1,3全都猜完就行了.
所以究竟是求什么呢? 要求猜的数组成的子序列中不能有两个凸起的部分,只能一边是单调函数,另一边也是单调函数.
代码:
#include <bits/stdc++.h>
using namespace std;
#define SZ(X) ((int)X.size())
#define mp make_pair
#define pb push_back
#define RALL(X) X.rbegin(),X.rend()
#define ALL(X) X.begin(),X.end()
using ll = long long ;
using ld = long double ;
const int N = 1E5 + 7;
const int INF = 0x3f3f3f3f;
int a[N];
int dp1[N];
int dp2[N];
int f1[N];
int f2[N];
int n, q;
int main()
{
scanf("%d %d", &q, &n);
for(int i = 1;i <= q;i ++) {
int l, r;
scanf("%d %d",&l, &r);
a[l] ++;
a[r+1] --;
}
for(int i = 1;i <= n;i ++) a[i] += a[i-1];
int len = 1;
fill(dp1+1, dp1+1+n, INF);
fill(dp2+1, dp2+1+n, -INF);
dp1[1] = a[1];
f1[1] = 1;
for(int i = 2;i <= n;i ++) {
if(a[i] >= dp1[len]) {
dp1[++len] = a[i];
} else {
int pos = upper_bound(dp1 + 1, dp1 + 1 + len, a[i]) - dp1;
dp1[pos] = a[i];
}
f1[i] = len;
}
len = 1;
dp2[1] = a[n];
for(int i = n - 1;i >= 1;i --) {
if(a[i] >= dp2[len]) {
dp2[++len] = a[i];
} else {
int pos = upper_bound(dp2 + 1, dp2 + 1 + len, a[i]) - dp2;
dp2[pos] = a[i];
}
f2[i] = len;
}
int res = 0;
for(int i = 1;i <= n;i ++) res = max(res, f1[i]+f2[i]-1);
printf("%d\n", res);
return 0;
}