2016 Multi-University Training Contest 1 D HDU 5762 GCD

题意:给你n个数,然后m个询问,每个询问两个数字l,r,输出x,y,
x=gcd(al,,al+1,...,ar),y表示有多少组l,r使得gcd(al,,al+1,...,ar)=x

思路:x很容易求,直接用线段树即可,求y需要预处理一下,n个数求得的gcd的种类数最多是log2n个,可以用map存一下r=i(a[i])与l前面l<=i(a[i])可以得到的gcd种类及其个数(r是固定的,l<=r);

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll a[500000+10];
 5 char str[10];
 6 struct node
 7 {
 8     int l,r;
 9     ll sum;
10 }tree[4*500000+10];
11 map<ll,ll>mp1,mp2,cnt;//a[i-1]的gcd种类及个数,a[i]的gcd种类及个数,gcd为i的l,r对数
12 map<ll,ll>::iterator it;
13 ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
14 void build(int l,int r,int node)
15 {
16     tree[node].l=l,tree[node].r=r;
17     if(l==r)
18     {
19         tree[node].sum=a[l];
20         return ;
21     }
22      int mid=(l+r)>>1;
23      build(l,mid,node<<1);
24      build(mid+1,r,node<<1|1);
25      tree[node].sum=gcd(tree[node<<1].sum,tree[node<<1|1].sum);
26     // printf("%d %lld\n",node,tree[node].sum);
27 }
28 ll cal(int l,int r,int node)
29 {
30     if(l==tree[node].l&&r==tree[node].r)
31     {
32         return tree[node].sum;
33     }
34     int mid=(tree[node].l+tree[node].r)>>1;
35     if(r<=mid)//当前寻找的区间在当前区间左边
36     {
37         return cal(l,r,node<<1);
38     }
39     else if(l>mid)//当前寻找的区间在当前区间右边
40         return cal(l,r,node<<1|1);
41     ll x,y;
42     x=cal(l,mid,node<<1);
43     y=cal(mid+1,r,node<<1|1);
44     return gcd(x,y);//当前寻找的区间在当前区间中间,则将寻找的区间拆分
45 }
46 int main()
47 {
48     int t;
49     scanf("%d",&t);
50     for(int kase=1;kase<=t;kase++)
51     {
52         printf("Case #%d:\n",kase);
53         int n;
54         scanf("%d",&n);
55         for(int i=1;i<=n;i++)
56         {
57             scanf("%lld",&a[i]);
58         }
59         cnt.clear(),mp2.clear(),mp1.clear();
60         for(int i=1;i<=n;i++)
61         {
62             cnt[a[i]]++;
63             mp2[a[i]]++;
64             for(it=mp1.begin();it!=mp1.end();it++)
65             {
66                 ll k=__gcd(a[i],it->first);
67                 cnt[k]+=it->second;
68                 mp2[k]+=it->second;
69             }
70             mp1.clear();
71             for(it=mp2.begin();it!=mp2.end();it++)
72             {
73                 mp1[it->first]=it->second;
74             }
75             mp2.clear();
76         }
77         build(1,n,1);
78         int m;
79         scanf("%d",&m);
80         while(m--)
81         {
82             int x,y,xx;
83             xx=min(x,y);
84             y=max(x,y);
85             x=xx;
86             scanf("%d %d",&x,&y);
87             printf("%lld %lld\n",cal(x,y,1),cnt[cal(x,y,1)]);
88         }
89 
90     }
91     return 0;
92 }
代码呀

猜你喜欢

转载自www.cnblogs.com/xtuteam222/p/9103039.html