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 */

时间: 2024-08-13 02:52:19

codeforces 359D 二分答案+RMQ的相关文章

Codeforces 1132D(二分答案+堆)

题面 传送门 分析 二分答案,考虑如何判定 可以用贪心的方法,每次找最快没电的电脑,在没电前1单位时间给它充电 正确性显然 实现上可以维护一个堆,存储每个电脑电用完的时刻,每次从堆顶取出最小的一个给它充电.设二分值为mid,对于每个电脑记录它的充电次数num[i],则没电的时间就是\(\lfloor \frac{a_i+num_i\times mid}{b_i} \rfloor+1\) 如果在维护堆的过程中发现当前时间已经超过某个电脑的没电时间,则返回false 代码 #include<iost

Electric Charges CodeForces - 623C (二分答案)

大意: 平面上n个点每个点坐标为(x,0)或(0,y), 求任意两点距离平方最大值的最小值. 二分答案, 转化为判定最大值是否<=e, 按$x$排序后, 因为固定左端点, $y$绝对值的最大值是跟右端点单调的, 滑动一个长度平方不超过e的区间, 同时保证右端点$x$的绝对值不超过左端点, 这样对于左端点在$x$轴的情况一定是最优的, 同样再固定右端点倒序处理正半轴的情况. #include <iostream> #include <random> #include <a

CodeForces 359D (数论+二分+ST算法)

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47319 题目大意:给定一个序列,要求确定一个子序列,①使得该子序列中所有值都能被其中一个值整除,②且子序列范围尽可能大(r-l尽可能大). 解题思路: 对于要求1,不难发现只有min(L,R)=gcd(L,R)时才行.其中gcd是L,R范围内的最大公约数,min是L,R范围内的最小值. 对于要求2,传统思路是r-l从大到小枚举,每次确定一个(L,R)范围,进行判

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

Codeforces 700A As Fast As Possible(二分答案)

[题目链接] http://codeforces.com/problemset/problem/700/A [题目大意] 有一辆限载k人速度为v2的车,n个步行速度均为v1的人要通过一段长度为l的距离,每个人只能上车一次,车可以来回走,问所有人到达目的地所需要的最短时间是多少 [题解] 因为车可以载k个人,所以,我们把人k个为一组分成(n+k-1)/k组,记为p吗,设需要的最短时间为t,每个人在车上待的时间为t2,那么可以列方程v1*(t-t2)+v2*t2=l,我们可以发现t2可以用t来表示,

Codeforces Round #425 (Div. 2) Problem C (Codeforces 832C) Strange Radiation - 二分答案 - 数论

n people are standing on a coordinate axis in points with positive integer coordinates strictly less than 106. For each person we know in which direction (left or right) he is facing, and his maximum speed. You can put a bomb in some point with non-n

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序 题意 有 a[ i ] 个数 要求选最多的数 使其和不超过 S ,且在此情况下,和最小选最多数情况下 和最小 且 每个数有加成 如果选了 k个数 那么加成后 就是 a[ i ] + k*i ; 题解 二分mid 表示选了个数 加成一下,将加成以后结果排序一下 , 若前 mid数 和大于 s 则此方案不可行 PS 要用 long long ..... 还有 co

Codeforces 460C prsent(二分答案)

//题意:给定N朵花的原先的高度,从左到右排列, //最多浇水m天,每天只能浇一次,每次使得连续的w朵花的高度增长1,问最后最矮的花的高度最高是多少. # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int main() { __int64 n,m,w,l,r,i,m1,sum; __int64 a[200010],b[200010]; while(~

Educational Codeforces Round 21 Problem F (Codeforces 808F) - 最小割 - 二分答案

Digital collectible card games have become very popular recently. So Vova decided to try one of these. Vova has n cards in his collection. Each of these cards is characterised by its power pi, magic number ci and level li. Vova wants to build a deck