CodeForces 359D (数论+二分+ST算法)
題目鏈接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47319
題目大意:給定一個序列,要求確定一個子序列,①使得該子序列中所有值都能被其中一個值整除,②且子序列范圍盡可能大(r-l盡可能大)。
解題思路:
對于要求1,不難發(fā)現(xiàn)只有min(L,R)=gcd(L,R)時才行。其中g(shù)cd是L,R范圍內(nèi)的最大公約數(shù),min是L,R范圍內(nèi)的最小值。
對于要求2,傳統(tǒng)思路是r-l從大到小枚舉,每次確定一個(L,R)范圍,進行判斷,直到可行。復(fù)雜度O(n^2)鐵定TLE。
由于r-l的值是有序的,固采用二分。先枚舉r-l的中間值,如果符合要求,則向右考慮,看看有沒有更大的。否則向左。
當(dāng)然這題的難度不止于此,盡管采用二分,但是光是枚舉復(fù)雜度就有O(nlogn)了,再加上查詢orz。
最初我使用的是線段樹完成RMQ、以及GCD的Query , 復(fù)雜度O(n*logn*logn), CF跑到Test10就TLE了。
看了題解才發(fā)現(xiàn)要使用ST算法在O(1)的時間內(nèi)完成RMQ和GCD。也是第一次碰到ST算法,看見劉汝佳的炒雞簡潔ST,給跪了。
?
#include "cstdio" #include "iostream" #include "vector" #include "algorithm" #include "math.h" #include "cstring" using namespace std; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define maxn 3*100005 #define maxp 20 template <class T> inline bool read(T &ret) {char c;int sgn;if(c=getchar(),c==EOF) return 0; //EOFwhile(c!='-'&&(c<'0'||c>'9')) c=getchar();sgn=(c=='-')?-1:1;ret=(c=='-')?0:(c-'0');while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');ret*=sgn;return 1; } int gcd(int a,int b) {if(b!=0) return gcd(b,a%b);else return a;} int RMQ[maxn][maxp],GCD[maxn][maxp],val[maxn],n,cnt,range; vector<int> ans; void ST() {for(int i=1;i<=n;i++) RMQ[i][0]=GCD[i][0]=val[i];for(int j=1;(1<<j)<=n;j++)for(int i=1;i+(1<<j)-1<=n;i++){RMQ[i][j]=min(RMQ[i][j-1],RMQ[i+(1<<(j-1))][j-1]);GCD[i][j]=gcd(GCD[i][j-1],GCD[i+(1<<(j-1))][j-1]);} } bool Query(int L,int R) {int k=0;while((1<<(k+1))<=R-L+1) k++;int a=min(RMQ[L][k],RMQ[R-(1<<k)+1][k]);int b=gcd(GCD[L][k],GCD[R-(1<<k)+1][k]);if(a==b) return true;else return false; } bool judge(int v) //枚舉r-l {int cc=0;vector<int> tt;for(int i=1; v+i<=n; i++){if(Query(i,i+v)) //L=i,R=i+v; {cc++;tt.push_back(i);}}if(cc>0){ans=tt;cnt=cc;range=v;return true;}return false; } int main() {memset(RMQ,1,sizeof(RMQ));memset(GCD,1,sizeof(GCD));read(n);for(int i=1; i<=n; i++)read(val[i]);ST();int l=0,r=n-1,mid;while(l<=r) //二分 {mid=(l+r)>>1;if(judge(mid)) l=mid+1;else r=mid-1;}printf("%d %d\n",cnt,range);for(int i=0;i<ans.size();i++) {if(i>0) printf(" ");printf("%d",ans[i]);};printf("\n"); }?
| 2808371 | neopenx | CodeForces 359D | Accepted | 51924 KB | 358 ms | GNU C++ 4.6 | 1981 B | 2014-10-03 15:00:32 |
?
???
?
總結(jié)
以上是生活随笔為你收集整理的CodeForces 359D (数论+二分+ST算法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苏宁易购发布半年度业绩预告,苏宁易购零售
- 下一篇: 【php】用filter_var实现的简