Pair of Numbers

题意:

给一长度为n的正整数序列,对于一个$[l,r]$,如果存在$d ∈ [l,r]$ 满足 $a(d)|a(i) (i∈[l, r])$ 则称之为合法子串。

找出所有的最长合法子串。

解法:

1. $O(n sum_{i=1}^n { au ( a(i) ) })$ 做法,枚举a序列中出现的数字d,将 i*d 所在的位置标上1,

然后从所有d所在的位置左右暴力拓展。

注意到只有下一位为1时才会拓展,所以暴力拓展的复杂度和标1的复杂度相同。

考虑每个数字a(i),最多被访问了它的约数次,所以总复杂度 $O(n sum_{i=1}^n { au ( a(i) ) })$

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <algorithm>
 6 
 7 #define N 300010
 8 #define M 1000010
 9 
10 using namespace std;
11 
12 int n,m,tot,ans,a[N],a0[N];
13 bool v[N],del[N];
14 vector<int> pos[M],ansv;
15 
16 int main()
17 {
18 //    freopen("test.txt","r",stdin);
19     while(~scanf("%d",&n))
20     {
21         for(int i=1;i<=n;i++) del[i]=0;
22         ansv.clear();
23         ans=m=1;
24         for(int i=1;i<=n;i++)
25         {
26             scanf("%d",&a[i]);
27             m = max(m, a[i]);
28             pos[a[i]].push_back(i);
29             a0[i]=a[i];
30         }
31         sort(a0+1,a0+n+1);
32         tot=1;
33         for(int i=2;i<=n;i++)
34             if(a0[i]!=a0[i-1]) a0[++tot]=a0[i];
35         for(int d=1;d<=tot;d++)
36         {
37             int x=a0[d];
38         //    cout <<"tet "<< x << endl;
39             for(int i=x;i<=m;i+=x)
40             {
41                 int nl=pos[i].size();
42                 for(int j=0;j<nl;j++) v[pos[i][j]]=1;
43             }
44             int len=pos[x].size();
45         //    for(int i=1;i<=n;i++) cout<<v[i];
46         //    cout<<endl;
47             for(int i=0;i<len;i++)
48             {
49                 int tmp=pos[x][i];
50                 if(del[tmp]) continue;
51                 del[tmp]=1;
52                 int l=tmp,r=tmp;
53                 while(l>1 && v[l-1])
54                 {
55                     l--;
56                     if(a[l] == x) del[l]=1;
57                 }
58                 while(r<n && v[r+1])
59                 {
60                     r++;
61                     if(a[r] == x) del[r]=1;
62                 }
63                 if(r-l+1>ans)
64                 {
65                     ans=r-l+1;
66                     ansv.clear();
67                     ansv.push_back(l);
68                 }
69                 else if(r-l+1==ans)
70                     ansv.push_back(l);
71             }
72             for(int i=x;i<=m;i+=x)
73             {
74                 int nl=pos[i].size();
75                 for(int j=0;j<nl;j++) v[pos[i][j]]=0;
76             }
77         }
78         for(int i=1;i<=m;i++) pos[i].clear();
79         int len=ansv.size();
80         cout << len << ' ' << ans-1 << endl;
81         sort(ansv.begin(), ansv.end());
82         for(int i=0;i<len;i++) cout << ansv[i] << ' ';
83         cout << endl;
84     }
85     return 0;
86 }
View Code

2.考虑优化上一个做法,将a(i)按照一定的顺序枚举,用类似对a(i)做筛法的方式,由a(i)推到i*a(i),这样均摊复杂度大概是

$O(nloglogn)$

3.仔细观察,从小到大枚举a(i),对于每一个a(i)暴力向左向右拓展,并记录相应位置是否被拓展到过,

对于当前枚举到的值为 a(i) 的位置

  (1)如果其向左 / 向右拓展到了标记过的位置,那一定无法再次拓展。

  (2)如果相应位置已经被访问过,那么从当前位置拓展,答案一定会变差。

这样,我们只要枚举a(i),暴力拓展即可。

每个位置只会被访问一次 且 每个数字被访问一次,总复杂度 $O(m)$ (懒得加桶排了)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <algorithm>
 6 
 7 #define N 300010
 8 #define M 1000010
 9 
10 using namespace std;
11 
12 int n,m,tot,ans,a[N],a0[N];
13 bool del[N];
14 vector<int> pos[M],ansv;
15 
16 int main()
17 {
18 //    freopen("test.txt","r",stdin);
19     while(~scanf("%d",&n))
20     {
21         for(int i=1;i<=n;i++) del[i]=0;
22         ansv.clear();
23         ans=m=1;
24         for(int i=1;i<=n;i++)
25         {
26             scanf("%d",&a[i]);
27             m = max(m, a[i]);
28             pos[a[i]].push_back(i);
29             a0[i]=a[i];
30         }
31         sort(a0+1,a0+n+1);
32         tot=1;
33         for(int i=2;i<=n;i++)
34             if(a0[i]!=a0[i-1]) a0[++tot]=a0[i];
35         for(int d=1;d<=tot;d++)
36         {
37             int x=a0[d];
38             int len=pos[x].size();
39             for(int i=0;i<len;i++)
40             {
41                 int tmp=pos[x][i];
42                 if(del[tmp]) continue;
43                 del[tmp]=1;
44                 int l=tmp,r=tmp;
45                 while(l>1 && a[l-1]%x==0) del[--l]=1;
46                 while(r<n && a[r+1]%x==0) del[++r]=1;
47                 if(r-l+1>ans)
48                 {
49                     ans=r-l+1;
50                     ansv.clear();
51                     ansv.push_back(l);
52                 }
53                 else if(r-l+1==ans)
54                     ansv.push_back(l);
55             }
56         }
57         for(int i=1;i<=m;i++) pos[i].clear();
58         int len=ansv.size();
59         cout << len << ' ' << ans-1 << endl;
60         sort(ansv.begin(), ansv.end());
61         for(int i=0;i<len;i++) cout << ansv[i] << ' ';
62         cout << endl;
63     }
64     return 0;
65 }
View Code
原文地址:https://www.cnblogs.com/lawyer/p/6484578.html