Codeforces Round #271 (Div. 2) F. Ant colony (RMQ or 线段树)

本文解析了CodeForces上的一道题目F,通过求解区间内的最大公约数(GCD),并使用线段树和RMQ技术快速查找符合条件的元素数量,最终计算出特定条件下区间的解。

题目链接:http://codeforces.com/contest/474/problem/F

题意简而言之就是问你区间l到r之间有多少个数能整除区间内除了这个数的其他的数,然后区间长度减去数的个数就是答案。

要是符合条件的话,那这个数的大小一定是等于gcd(a[l]...a[r])。

我们求区间gcd的话,既可以利用线段树性质区间递归下去然后返回求解,但是每次查询是log的,所以还可以用RMQ,查询就变成O(1)了。

然后求解区间内有多少个数的大小等于gcd的话,也是利用线段树的性质,区间递归求解之,复杂度也是log的。

 1 //#pragma comment(linker, "/STACK:102400000, 102400000")
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <ctime>
10 #include <list>
11 #include <set>
12 #include <map>
13 using namespace std;
14 typedef long long LL;
15 typedef pair <int, int> P;
16 const int N = 1e5 + 5;
17 int gcd[N][20];
18 struct SegTree {
19     int l , r , Min , num;
20 }T[N << 3];
21 
22 int GCD(int a, int b) {
23     return b ? GCD(b, a % b) : a;
24 }
25 
26 void ST(int n) {
27     for(int k = 1; k < 20; ++k) {
28         for(int i = 1; i + (1 << k) - 1 <= n; ++i) {
29             gcd[i][k] = GCD(gcd[i][k - 1], gcd[i + (1 << (k - 1))][k - 1]);
30         }
31     }
32 }
33 
34 void build(int p , int l , int r) {
35     int mid = (l + r) >> 1;
36     T[p].l = l , T[p].r = r , T[p].num;
37     if(l == r) {
38         T[p].Min = gcd[l][0];
39         T[p].num = 1;
40         return ;
41     }
42     build(p << 1 , l , mid);
43     build((p << 1)|1 , mid + 1 , r);
44     if(T[p << 1].Min == T[(p << 1)|1].Min) {
45          T[p].Min = T[p << 1].Min;
46          T[p].num = T[p << 1].num + T[(p << 1)|1].num;
47     }
48     else if(T[p << 1].Min < T[(p << 1)|1].Min) {
49         T[p].Min = T[p << 1].Min;
50         T[p].num = T[p << 1].num;
51     }
52     else {
53         T[p].Min = T[(p << 1)|1].Min;
54         T[p].num = T[(p << 1)|1].num;
55     }
56 }
57 
58 int query(int p , int l , int r , int g) {
59     int mid = (T[p].l + T[p].r) >> 1;
60     if(T[p].l == l && T[p].r == r) {
61         return T[p].Min == g ? T[p].num : 0;
62     }
63     if(r <= mid) {
64         return query(p << 1 , l , r , g);
65     }
66     else if(l > mid) {
67         return query((p << 1)|1 , l , r , g);
68     }
69     else {
70         return query(p << 1 , l , mid , g) + query((p << 1)|1 , mid + 1 , r , g);
71     }
72 }
73 
74 int main()
75 {
76     int n, q, l, r;
77     scanf("%d", &n);
78     for(int i = 1; i <= n; ++i)
79         scanf("%d", &gcd[i][0]);
80     ST(n);
81     build(1 , 1 , n);
82     scanf("%d", &q);
83     while(q--) {
84         scanf("%d %d", &l, &r);
85         int k = log2(r - l + 1);
86         int g = GCD(gcd[l][k], gcd[r - (1 << k) + 1][k]);
87         printf("%d\n", r - l + 1 - query(1 , l , r , g));
88     }
89     return 0;
90 }

 

转载于:https://www.cnblogs.com/Recoder/p/5711993.html

乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值