题意
有一条线段,上面的点被若干条线段覆盖着. Sasha想知道是否存在一个整点被所有的线段覆盖,她每次可以任选一个点,Teodor会告诉她这个点被多少个线段覆盖。Sasha不知道有多少条线段。求Sasha最多猜多少次还不知道这个问题的答案。也就是说,如果你最多猜x次能知道答案,输出x-1。
特别的,如果猜不到答案就输出n。
分析
其实翻译起来挺麻烦理解起来有点怕理解错了[?]
其实可以容易的发现,如果所有的点连起来是一个单峰(非降序列+非增序列拼在一起),那么就猜不到答案。但是如果连起来不是单峰而是多峰的话,那么马上就能知道答案了。
所以说,其实就是找到一个最长的单峰。
然后这个通过dp就可以解决了,考虑一个点最大,然后往两遍递减,然后求最长长度就好了。通过树装数组求lis一样的东西,总之很好解决。
code
#include<bits/stdc++.h>
using namespace std;
void read(int &x){
x=0; char c=getchar();
for (;c<48;c=getchar());
for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
#define M 1000005
int f[M],m,g[M],cnt[M];
void Max(int &x,int y){
if (x<y)x=y;
}
struct Tree{
#define lowbit(p) (p&(-p))
int a[M];
void add(int p,int x){
for (;p<M;p+=lowbit(p))Max(a[p],x);
}
int qu(int p){
int res=0;
for (;p;p-=lowbit(p))Max(res,a[p]);
return res;
}
void clear(){
memset(a,0,sizeof(a));
}
}T;
int main(){
// freopen("1.in","r",stdin);
int n,res,l,r;
read(n); read(m);
for (int i=1;i<=n;i++){
read(l); read(r);
cnt[l]++; cnt[r+1]--;
}
cnt[1]++;
for (int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for (int i=1;i<=m;i++){
f[i]=T.qu(cnt[i])+1;
T.add(cnt[i],f[i]);
}
T.clear();
for (int i=m;i;i--){
g[i]=T.qu(cnt[i])+1;
T.add(cnt[i],g[i]);
}
for (int i=1;i<=m;i++)Max(res,f[i]+g[i]-1);
printf("%d\n",res);
return 0;
}
总结
简单来说就是看题目的时候不要怕吧…其实没有想象的那么困难。
常数
其实挺优秀的[?]
其实是所有人好像都跑这么快…