HDU 5869 Different GCD Subarray Query

原题链接:HDU-5869

题意为给定一组数和一组询问,每个询问用一个区间表示,要求输出区间内所有连续子序列的不同gcd值。

这道题和HDU-3333非常像。区别在于这里需要处理的是gcd。而gcd有一个性质,即相同起点的序列的gcd非严格递减。

对比HDU-3333,这道题需要使每个gcd对应序列的左起点尽量向右。

扫描到位置i的时候,可以新得到的gcd只与前面的i-1个数有关,但事实上能产生的新gcd是有限的,大概有( log a_i )个。所以用gcds[][]存起来,每次用gcd[i-1]更新gcd[i]即可。

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 #define MAXN 100010
 6 #define MAXM 100010
 7 
 8 int gcd(int a,int b)
 9 {
10     if(b==0) return a;
11     return gcd(b,a%b);
12 }
13 int d[MAXN];
14 int n,m;
15 vector<pair<int,int> > q[MAXM];
16 vector<pair<int,int> > gcds[MAXN];
17 int vis[1000010];
18 int ans[MAXM];
19 int tree[MAXN];
20 int lowbit(int x)
21 {
22     return x&(-x);
23 }
24 void add(int k,int num)
25 {
26     while(k<=n)
27     {
28         tree[k]+=num;
29         k+=lowbit(k);
30     }
31 }
32 int sum(int k)
33 {
34     int ans=0;
35     while(k)
36     {
37         ans+=tree[k];
38         k-=lowbit(k);
39     }
40     return ans;
41 }
42 int main()
43 {
44 #ifdef LOCAL
45     freopen("in.txt","r",stdin);
46 #endif
47     while(scanf("%d%d",&n,&m)!=EOF)
48     {
49         for(int i=0;i<=n;i++) gcds[i].clear();
50         for(int i=1;i<=n;i++) q[i].clear();
51         memset(vis,0,sizeof(vis));
52         memset(tree,0,sizeof(tree));
53         for(int i=1;i<=n;i++) scanf("%d",&d[i]);
54         for(int i=1;i<=m;i++)
55         {
56             int l,r;
57             scanf("%d%d",&l,&r);
58             q[r].push_back(make_pair(l,i));
59         }
60         for(int i=1;i<=n;i++)
61         {
62             if(vis[d[i]]) add(vis[d[i]],-1);
63             add(i,1);
64             vis[d[i]]=i;
65             gcds[i].push_back(make_pair(d[i],i));
66             for(unsigned int j=0;j<gcds[(i-1)].size();j++)
67             {
68                 int tmp1=gcd(gcds[(i-1)][j].first,d[i]),tmp2=gcds[(i-1)][j].second;
69                 if(tmp1==gcds[i][gcds[i].size()-1].first) continue;
70                 if(vis[tmp1]) add(vis[tmp1],-1);
71                 add(tmp2,1);
72                 vis[tmp1]=tmp2;
73                 gcds[i].push_back(make_pair(tmp1,tmp2));
74             }
75             for(unsigned int j=0;j<q[i].size();j++)
76             {
77                 int tmp=q[i][j].second;
78                 ans[tmp]=sum(i)-sum(q[i][j].first-1);
79             }
80         }
81         for(int i=1;i<=m;i++) printf("%d
",ans[i]);
82     }
83     return 0;
84 }
原文地址:https://www.cnblogs.com/zarth/p/6366182.html