1. 程式人生 > >Teodor is not a liar! [CodeForces - 930C]

Teodor is not a liar! [CodeForces - 930C]

題意

有一條線段,上面的點被若干條線段覆蓋著. 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; }

總結

簡單來說就是看題目的時候不要怕吧…其實沒有想象的那麼困難。

常數

其實挺優秀的[?]
其實是所有人好像都跑這麼快…