Teodor is not a liar! [CodeForces - 930C]
阿新 • • 發佈:2018-12-24
題意
有一條線段,上面的點被若干條線段覆蓋著. 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;
}
總結
簡單來說就是看題目的時候不要怕吧…其實沒有想象的那麼困難。
常數
其實挺優秀的[?]
其實是所有人好像都跑這麼快…