gcd区间

https://vjudge.net/contest/237352#problem/A

题意:给出n个数,q个询问,对于每个询问xi,求有多少个子区间,区间内的gcd为xi,分别输出个数。

解法:一段区间,每在末尾增加一个数,区间gcd要么保持原状,要么至少缩小为原来的一半,所以对于1e9的数,区间不同的gcd值至多有log(1e9)个。

枚举右区间,对于每个右区间(i,r),用map存区间(1,r), (2,r) ... (r,r) 的gcd值,又知map的大小不超过100。每次右区间增加1,就可以通过r-1的map得到r的map,更新map,更新答案,如此类推,右区间从1枚举至n。

 1 #include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <string>
 7 #include <cmath>
 8 #include <cstdlib>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <vector>
13 #include <set>
14 #include <bitset>
15 #include <iomanip>
16 #define ms(a, b) memset(a, b, sizeof(a));
17 using namespace std;
18 typedef long long LL;
19 typedef pair<int, int> pii;
20 const int INF = 0x3f3f3f3f;
21 const int maxn = 1e2 + 10;
22 const int MAXN = 2e4 + 10;
23 const double eps = 1e-8;
24 const int mod = 1e9 + 7;
25 int n, q;
26 map<int, int> cnt1, cnt2;
27 map<int, LL> ans;
28 
29 int gcd(int a, int b) {
30     return b == 0 ? a : gcd(b, a % b);
31 }
32 
33 int main()
34 {
35 #ifdef local
36     freopen("case.in","r",stdin);
37 //    freopen("out.in","w",stdout);
38 #endif
39     scanf("%d", &n);
40     for(int i = 0; i < n; i++) {
41         int a;
42         scanf("%d", &a);
43         map<int, int>::iterator it;
44         for(it = cnt1.begin(); it != cnt1.end(); it++) {
45             cnt2[gcd(a, it->first)] += cnt1[it->first];
46         }
47         cnt2[a]++;
48         cnt1 = cnt2;
49         cnt2.clear();
50         for(it = cnt1.begin(); it != cnt1.end(); it++)
51             ans[it->first] += cnt1[it->first];
52     }
53     scanf("%d", &q);
54     for(int i = 0; i < q; i++) {
55         int x;
56         scanf("%d", &x);
57         printf("%lld\n", ans[x]);
58     }
59     return 0;
60 }

 

转载于:https://www.cnblogs.com/Sissi-hss/p/9471713.html

根据引用中的公式gcd(a,b) = gcd(a,b-a),可以得出gcd(a,b)的值等于gcd(a,b-a)的值。这意味着最大公约数可以通过连续对两个数的差值取最大公约数来计算。这个公式可以用于求解最大公约数的问题。 另外,根据引用中的代码,可以通过求解最小公倍数来计算gcd(a,b)。该代码使用了枚举b-a的因数i,然后通过计算a和b除以i的余数来得到一个k值,再使用k来计算最小公倍数lcm。如果存在多个k使得lcm最小,则输出最小的k。 综上所述,gcd(a,b) = gcd(a,b-a)是一个可以用于计算最大公约数的等式。它可以通过连续对两个数的差值取最大公约数来实现。此外,也可以通过求解最小公倍数来计算最大公约数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [区间gcd](https://blog.csdn.net/xumingyang0/article/details/88534039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Codeforces Round #554 (Div. 2) C. Neko does Maths (数论 GCD(a,b) = GCD(a,b-a))](https://blog.csdn.net/deoigfot051992/article/details/101587503)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值