Pentium.Labs

System全家桶:https://zhuanlan.zhihu.com/c_1238468913098731520

导航

codeforces 359D 二分答案+RMQ

上学期刷过裸的RMQ模板题,不过那时候一直不理解>_<

其实RMQ很简单:

设f[i][j]表示从i开始的,长度为2^j的一段元素中的最小值or最大值

那么f[i][j]=min/max{d[i][j-1], d[i+2^j-1][j-1]}

RMQ的ST算法:

 1 void ST()        //初始化
 2 {
 3     memset(RMQ,1,sizeof(RMQ));
 4 
 5     for(int i=1;i<=n;i++)
 6         RMQ[i][0]=a[i];
 7     for(int j=1;(1<<j)<=n;j++)
 8         for(int i=1;i+(1<<j)-1<=n;i++)
 9         RMQ[i][j]=min(RMQ[i][j-1],RMQ[i+(1<<(j-1))][j-1]);
10 }
11 
12 int Query(int L,int R)    //求a[L..R]区间的最值
13 {
14     int k=0;
15     while((1<<(k+1))<=R-L+1) k++;
16     int tb=gcd(GCD[L][k],GCD[R-(1<<k)+1][k]);
17     return tb;
18 }

 

-----------------------------------------------

再回到这道题。要求输出r-l的最大值

可以使用二分答案。

注意:r-l的值可以为0(即r==l),可以这样写:

1         l=0;    r=n;
2         while (r>=l)
3         {
4             int mid=(l+r)/2;    //mid: r-l
5             if (calc(mid))        //calc(mid): 判断mid答案是否符合要求
6                 l=mid+1;
7             else
8                 r=mid-1;
9         }

记得原来还刷过求最小值的二分答案(NOIP2010提高组  关押罪犯),是这样的:

 1 //当年的代码略屎= =
 2 
 3 sol:=false;
 4 l:=0;   r:=mx;
 5 while l<r do
 6  begin
 7  mid:=(l+r) div 2;
 8  ok:=process(mid);
 9  if ok then
10   begin
11   sol:=true;
12   r:=mid;
13   end
14  else
15   begin
16   l:=mid+1;
17   sol:=true;
18   end;
19  end;

----------------------------------------

如何求区间所有元素的gcd?

不难想出,其实gcd和min(求区间最小值)有个一样的性质:

设在区间[l..r]中,[l..k]的gcd为m,[k+1..r]的gcd为n,

则整个区间[l..r]的gcd等于gcd(m,n)

 

有了这个性质,就可以用ST算法求gcd了。

 

-------------------------------------------

借用了neopenx大神的RMQ模板,Orz

  1 #include <iostream>
  2 #include <vector>
  3 #include <cstring>
  4 using namespace std;
  5 
  6 vector<int> ans;
  7 int RMQ[301000][20],GCD[301000][20];
  8 int T,n,l,r,mx,num;
  9 int a[301000];
 10 
 11 int gcd(int x,int y)
 12 {
 13     return (y==0)?x:gcd(y,x%y);
 14 }
 15 
 16 void ST()
 17 {
 18     memset(RMQ,1,sizeof(RMQ));
 19     memset(GCD,1,sizeof(GCD));
 20 
 21     for(int i=1;i<=n;i++)
 22         RMQ[i][0]=GCD[i][0]=a[i];
 23     for(int j=1;(1<<j)<=n;j++)
 24         for(int i=1;i+(1<<j)-1<=n;i++)
 25     {
 26         RMQ[i][j]=min(RMQ[i][j-1],RMQ[i+(1<<(j-1))][j-1]);
 27         GCD[i][j]=gcd(GCD[i][j-1],GCD[i+(1<<(j-1))][j-1]);
 28     }
 29 }
 30 
 31 bool Query(int L,int R)
 32 {
 33     if (L==R) return true;
 34     int k=0;
 35     while((1<<(k+1))<=R-L+1) k++;
 36     int ta=min(RMQ[L][k],RMQ[R-(1<<k)+1][k]);
 37     int tb=gcd(GCD[L][k],GCD[R-(1<<k)+1][k]);
 38     if (ta==tb)   return true;
 39         else return false;
 40 }
 41 
 42 
 43 bool calc(int x)        //x: r-l
 44 {
 45     bool res=false;
 46     for (int i=1;i<=n-x;i++)
 47     {
 48         bool ok=Query(i,i+x);
 49         if (ok)
 50         {
 51             res=true;
 52             //cout<<"----"<<i<<" "<<i+x<<" "<<x<<endl;  //record the answer,use vector
 53             if (x==mx)
 54             {
 55                 num++;
 56                 ans.push_back(i);
 57             }
 58             else if (x>mx)
 59             {
 60                 num=1;
 61                 mx=x;
 62                 ans.clear();
 63                 ans.push_back(i);
 64             }
 65         }
 66     }
 67     return res;
 68 }
 69 
 70 int main()
 71 {
 72         mx=-1;
 73         num=0;
 74         ans.clear();
 75         cin>>n;
 76         for (int i=1;i<=n;i++)
 77             cin>>a[i];
 78 
 79         ST();
 80 
 81         l=0;    r=n;
 82         while (r>=l)
 83         {
 84             int mid=(l+r)/2;    //mid: r-l
 85             if (calc(mid))
 86                 l=mid+1;
 87             else
 88                 r=mid-1;
 89         }
 90         cout<<num<<" "<<mx<<endl;
 91             vector<int>::iterator ii;
 92             for (ii=ans.begin();ii!=ans.end();ii++)
 93                 cout<<*ii<<" ";
 94         cout<<endl;
 95 
 96     return 0;
 97 }
 98 
 99 
100 /*
101 注意特殊情况:
102 5
103 2 3 5 7 11
104 计算时应把r-l=0也考虑进去
105 (r==l)
106 */
View Code

 

posted on 2014-10-07 16:40  Pentium.Labs  阅读(334)  评论(0编辑  收藏  举报



Pentium.Lab Since 1998