JZOJ 3895. 数字对

题目

Description

小H是个善于思考的学生,现在她又在思考一个有关序列的问题。
她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。
这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。
小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。
 

Input

第一行,一个整数n.
第二行,n个整数,代表ai.

Output

第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。
第二行num个整数,按升序输出每个价值最大的特殊区间的L.
 

Sample Input

输入1:
5
4 6 9 3 6
输入2:
5
2 3 5 7 11

Sample Output

输出1:
1 3
2
输出2:
5 0
1 2 3 4 5
 

Data Constraint

30%: 1 <= n <= 30 , 1 <= ai <= 32.
60%: 1 <= n <= 3000 , 1 <= ai <= 1024.
80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.
100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.

 

分析

30% :暴力枚举判断。O(n^4)。 60% :特殊区间的特点实际上就是区间最小值等于这个区间的 GCD,于是暴力或递推算 出每个区间的最小值与 GCD。而对于最大价值,可以通过二分来进行求解。复杂 度 O(n ^ 2)。 100%:在 60%的基础上,最小值与 GCD 都使用 RMQ 算法来求解,对于这道题推荐使用 ST 表。最大价值仍然使用二分。复杂度 O(nlogn)。

  • 但是我是暴力过
  • 枚举节点k,向前找,向后找最大公约数
  • 加个快读就过了

 

代码

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M 500010
 6 using namespace std;
 7 long long n,a[M],mxx,mxl,sum,Ans[M];
 8 struct sb{
 9     int len,l;
10 }ans[M];
11 long long init(){
12     
13     int x=0;char s=getchar();
14     while(s<'0'||s>'9')s=getchar();
15     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
16     return x;
17 }
18 bool cmp(sb x,sb y){
19     if(x.len==y.len) return x.l<y.l;
20     return x.len>y.len;
21 }
22 long long Gcd(long long a,long long b){
23     if (b==0)
24     {
25         return a;
26     }
27     Gcd(b,a%b);
28 }
29 int main()
30 {
31     n=init();
32     for(int i=1;i<=n;i++)
33         a[i]=init();
34        for(int k=1;k<=n;k++)
35        {
36            int li=k,ri=k,gcd=a[k];
37            for(int i=k+1;i<=n;i++)
38            {
39                   if(Gcd(gcd,a[i])!=gcd) 
40                   break;
41                else ri++;
42            }
43            for(int i=k-1;i>=1;i--)
44            {
45                  if(Gcd(gcd,a[i])!=gcd)
46                   break;
47               else li--;
48            }
49                
50            ans[k].len=ri-li;
51            ans[k].l=li;
52         }
53         sort(ans+1,ans+1+n,cmp);
54         mxx=ans[1].len;mxl=ans[1].l;
55         Ans[++sum]=mxl;
56         for(int k=2;k<=n;k++)
57            if(ans[k].len!=mxx)
58                break;
59         else if(ans[k].l!=mxl)
60         {
61             Ans[++sum]=ans[k].l;
62             mxl=ans[k].l;
63         }
64     cout<<sum<<" "<<mxx<<endl;
65     for(int i=1;i<=sum;i++)
66         cout<<Ans[i]<<" ";
67     return 0;
68 }

 

 

posted @ 2019-01-25 21:55  Melted_czj  阅读(243)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色