BZOJphp
感受本身徹底沒作過環上選線段的問題(除了一個2-SAT),因此來具體寫一寫qwq。
基本徹底抄自remoon的題解qwq...html
(下標從\(0\sim m-1\))
拆環爲鏈,對於原線段\([l,r]\),若\(l\leq r\)就拆成兩個線段\([l,r],[l+m-1,r+m-1]\),不然拆成一個線段\([l,r+m-1]\)。(這樣枚舉的時候限制所選線段在一個\(m\)區間內就好了)
考慮暴力。直接枚舉是否必定選某個線段\(i\),而後貪心選其它的便可(限制所選線段在\([l_i,l_i+m-1]\)內)。複雜度\(O(n^2)\)或\(O(n^2\log n)\)。git
假設最優答案是\(x\)。若\(x\leq\sqrt n\),那麼每次最多會選\(x\)次。
若\(x\gt\sqrt n\),那麼每次隨機一個線段都會有\(\frac xn\)的機率選中最優解。因此咱們隨機\(\frac nx+\)次可能就差很少了。
可是咱們也不知道\(x\),寫第一種好像也很麻煩。那就用第二個隨機的那種作法好了。spa
設隨機的次數是\(k\),那麼複雜度是\(O(kn)\)的。
往大了取好了。事實上取\(k=2\)就能夠過這道題惹=v=。
雖然其實正確性並無保證=v=...code
//3656kb 280ms #include <cstdio> #include <cctype> #include <algorithm> #define Rand() (rand()<<16|rand()) #define gc() getchar() #define MAXIN 500000 //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) typedef long long LL; const int N=1e5+5; int L[N],R[N]; char IN[MAXIN],*SS=IN,*TT=IN; struct Node { int l,r; bool operator <(const Node &x)const { return r<x.r; } }A[N<<1]; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-48,c=gc()); return now; } int Calc(int x,int n,int m,int tot) { int ans=0; for(int i=1,now=0,l=L[x],r=l+m; i<=tot; ++i) if(A[i].l>=l && A[i].r<=r && A[i].l>=now) now=A[i].r, ++ans; return ans; } int main() { srand(1002330); const int m=read()-1,n=read(); int tot=0; for(int i=1; i<=n; ++i) { int l=L[i]=read(),r=R[i]=read();//我剛開始居然沒讀L[i] WA n次=-= if(l<=r) A[++tot]=(Node){l,r}, A[++tot]=(Node){l+m,r+m}; else A[++tot]=(Node){l,r+m}; } std::sort(A+1,A+1+tot); int ans=0; // for(int k=2,i=1; i<=n; i+=n/k) ans=std::max(ans,Calc(i,n,m,tot));//也可過... for(int k=100; k--; ) ans=std::max(ans,Calc(Rand()%n+1,n,m,tot)); printf("%d\n",ans); return 0; }