记录编号 130313 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [国家集训队 2012] 几乎平均数 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 31.414 s
提交时间 2014-10-21 22:43:50 内存使用 982.70 MiB
显示代码纯文本
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<vector>
  7. using namespace std;
  8. typedef long long LL;
  9. const LL INF=(LL)1e12;
  10. const int SIZEN=100010,SIZEK=320;
  11. LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
  12. class Frac{
  13. public:
  14. LL p,q;
  15. };
  16. inline Frac getFrac(LL a,LL b){
  17. LL g=gcd(a,b);
  18. a/=g,b/=g;
  19. if(b<0) a*=-1,b*=-1;
  20. return (Frac){a,b};
  21. }
  22. void print(Frac a){
  23. printf("%lld/%lld",a.p,a.q);
  24. }
  25. inline bool operator < (Frac a,Frac b){return (a.p+0.0)*(b.q+0.0)<(b.p+0.0)*(a.q+0.0);}
  26. inline Frac operator + (Frac a,Frac b){return getFrac(a.p*b.q+b.p*a.q,a.q*b.q);}
  27. inline Frac operator - (Frac a,Frac b){return getFrac(a.p*b.q-b.p*a.q,a.q*b.q);}
  28. inline Frac operator * (Frac a,Frac b){return getFrac(a.p*b.p,a.q*b.q);}
  29. class Point{
  30. public:
  31. double x,y;
  32. void print(void){cout<<"("<<x<<","<<y<<")";}
  33. };
  34. void print(Point p){cout<<"("<<p.x<<","<<p.y<<")";}
  35. inline Point operator - (Point a,Point b){return (Point){a.x-b.x,a.y-b.y};}
  36. inline double crp(Point a,Point b){
  37. return a.x*b.y-b.x*a.y;
  38. }
  39. int N,Q,SZ,K;
  40. LL X[SIZEN]={0},S[SIZEN]={0};
  41. int head[SIZEN]={0},tail[SIZEN]={0},belong[SIZEN]={0};
  42. Frac f[SIZEK][SIZEN],g[SIZEK][SIZEN];//f[i][j]:L=head[i],R=j的查询答案;g[i][j]:L=j,R=tail[i]的查询的答案
  43. class Convex_Hull_L_Active{
  44. public:
  45. //凸包是"上凸"的
  46. Point H[SIZEN];
  47. int n;//0~n-1,从右向左
  48. inline void clear(void){n=0;}
  49. inline void print(void){for(int i=n-1;i>=0;i--){H[i].print();cout<<" ";}cout<<endl;}
  50. inline void add(Point p){//p的横坐标小于H中的点
  51. while(n>=2&&crp(H[n-1]-p,H[n-2]-H[n-1])>=0) n--;
  52. H[n++]=p;
  53. }
  54. inline Frac calc(Point p){//p的横坐标小于H中的点,计算p和凸包上某点形成的最大斜率
  55. int l=0,r=n-1,mid;
  56. while(l<r){
  57. mid=(l+r)/2;
  58. if(crp(H[mid+1]-p,H[mid]-H[mid+1])>=0) r=mid;
  59. else l=mid+1;
  60. }
  61. return getFrac(H[l].y-p.y,H[l].x-p.x);
  62. }
  63. };
  64. class Convex_Hull_R_Active{//"右端活跃"的凸包
  65. public:
  66. //凸包是"下凸"的
  67. Point H[SIZEN];
  68. int n;//0~n-1,从左到右
  69. inline void clear(void){n=0;}
  70. inline void print(void){for(int i=0;i<n;i++){H[i].print();cout<<" ";}cout<<endl;}
  71. inline void add(Point p){//p的横坐标大于H中的点
  72. while(n>=2&&crp(p-H[n-2],H[n-1]-H[n-2])>=0) n--;
  73. H[n++]=p;
  74. }
  75. inline Frac calc(Point p){//p的横坐标大于H中的点,计算p和凸包上某点形成的最大斜率
  76. int l=0,r=n-1,mid;
  77. while(l<r){
  78. mid=(l+r)/2;
  79. if(crp(p-H[mid],H[mid+1]-H[mid])>=0) r=mid;
  80. else l=mid+1;
  81. }
  82. return getFrac(H[l].y-p.y,H[l].x-p.x);
  83. }
  84. };
  85. class Super_Hull{//把两种不同姿势的凸包打包成一个类......这是一种诡异的思路
  86. public:
  87. Convex_Hull_L_Active hull_L;
  88. Convex_Hull_R_Active hull_R;
  89. //type=0为左(上凸),type=1为右(下凸)
  90. void print(bool type){type?hull_R.print():hull_L.print();}
  91. inline void clear(bool type){type?hull_R.clear():hull_L.clear();}
  92. inline void add(int k,bool type){
  93. if(!type) hull_L.add((Point){k,S[k]});
  94. else hull_R.add((Point){k,S[k-1]});
  95. }
  96. inline Frac calc(int k,bool type){
  97. if(!type) return hull_L.calc((Point){k,S[k-1]});
  98. else return hull_R.calc((Point){k,S[k]});
  99. }
  100. }hull;
  101. Frac calc_seg(int l,int r){
  102. return getFrac(S[r]-S[l-1],r-l);
  103. }
  104. inline Frac calc(int a,int b){
  105. Frac ans=getFrac(-INF,1);
  106. if(belong[a]<K&&head[belong[a]+1]<b){
  107. if(ans<f[belong[a]+1][b]) ans=f[belong[a]+1][b];
  108. }
  109. if(belong[b]>1&&tail[belong[b]-1]>a){
  110. if(ans<g[belong[b]-1][a]) ans=g[belong[b]-1][a];
  111. }
  112. /*下面考虑:头在a的块,尾在b的块内的情况,这时我们采用的思路是,
  113. 将右端的元素加入凸包后枚举答案的左端点,因而凸包左活跃,操作代码0*/
  114. int l_end=min(b-1,tail[belong[a]]),r_end=max(a+1,head[belong[b]]);
  115. hull.clear(0);
  116. int k=l_end;
  117. for(int i=b;i>=r_end;i--){
  118. hull.add(i,0);
  119. if(k==i-1){
  120. Frac tmp=hull.calc(k,0);
  121. if(ans<tmp) ans=tmp;
  122. k--;
  123. }
  124. }
  125. for(;k>=a;k--){
  126. Frac tmp=hull.calc(k,0);
  127. if(ans<tmp) ans=tmp;
  128. }
  129. return ans;
  130. }
  131. void DP_prepare(void){
  132. //计算f,即向后的情况,这时是向凸包的尾端插入,凸包右活跃,操作代码1
  133. for(int i=1;i<=K;i++){
  134. //该块中元素压入凸包
  135. hull.clear(1);
  136. for(int j=head[i];j<=tail[i];j++){
  137. if(j>head[i]) f[i][j]=hull.calc(j,1);
  138. hull.add(j,1);
  139. }
  140. for(int j=tail[i]+1;j<=N;j++) f[i][j]=hull.calc(j,1);
  141. for(int j=head[i]+1;j<=N;j++) if(f[i][j]<f[i][j-1]) f[i][j]=f[i][j-1];
  142. }
  143. for(int i=K-1;i>=1;i--){
  144. for(int j=head[i+1];j<=N;j++){
  145. if(f[i][j]<f[i+1][j]) f[i][j]=f[i+1][j];
  146. }
  147. }
  148. //计算g,即向前的情况,这时是向凸包的头部加入,凸包左活跃,操作代码0
  149. for(int i=K;i>=1;i--){
  150. //该块中元素压入凸包
  151. hull.clear(0);
  152. for(int j=tail[i];j>=head[i];j--){
  153. if(j<tail[i]) g[i][j]=hull.calc(j,0);
  154. hull.add(j,0);
  155. }
  156. for(int j=head[i]-1;j>=1;j--) g[i][j]=hull.calc(j,0);
  157. for(int j=tail[i]-1;j>=1;j--) if(g[i][j]<g[i][j+1]) g[i][j]=g[i][j+1];
  158. }
  159. for(int i=2;i<=K;i++){
  160. for(int j=1;j<=tail[i-1];j++){
  161. if(g[i][j]<g[i-1][j]) g[i][j]=g[i-1][j];
  162. }
  163. }
  164. }
  165. void work(void){
  166. int a,b;
  167. for(int i=1;i<=Q;i++){
  168. scanf("%d%d",&a,&b);
  169. print(calc(a,b));
  170. printf("\n");
  171. }
  172. }
  173. void read(void){
  174. scanf("%d%d",&N,&Q);
  175. for(int i=1;i<=N;i++) scanf("%lld",&X[i]),S[i]=S[i-1]+X[i];
  176. SZ=sqrt(N+0.5)*3;
  177. K=head[1]=1;
  178. int tot=0;
  179. for(int i=1;i<=N;i++){
  180. belong[i]=K;
  181. tot++;
  182. if(tot==SZ||i==N){
  183. tail[K]=i;
  184. K++;
  185. tot=0;
  186. head[K]=i+1;
  187. }
  188. }
  189. K--;
  190. }
  191. int main(){
  192. freopen("almost.in","r",stdin);
  193. freopen("almost.out","w",stdout);
  194. read();
  195. DP_prepare();
  196. work();
  197. return 0;
  198. }