2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (线段树+GCD)

Posted scaulok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (线段树+GCD)相关的知识,希望对你有一定的参考价值。

题目链接:https://codeforces.com/gym/101991/problem/G

题意:给出 n 个数,q 次询问区间[ li,ri ]之间有多少个 GCD = di 的连续子区间。

题解:类似HDU 5726,可以先看一下这个blog:https://blog.csdn.net/u013569304/article/details/51987053

考虑离线,先预处理出[ 1,n ]之间所有的GCD,同时需要记录每种 GCD 的区间,方法是固定一个右端点R,对于区间[ L,R ],假设 GCD(L,R)= D,可以找到使得GCD(L,R)突变的点 pos,即 x ∈ [ L,pos ] 都有 GCD(x,R) = D,然后利用线段树可以统计出 GCD = D 的区间个数。

 

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define ull unsigned long long
  5 #define mst(a,b) memset((a),(b),sizeof(a))
  6 #define mp(a,b) make_pair(a,b)
  7 #define pi acos(-1)
  8 #define pii pair<int,int>
  9 #define pb push_back
 10 const int INF = 0x3f3f3f3f;
 11 const double eps = 1e-6;
 12 const int maxn = 1e5 + 10;
 13 const int maxm = 1e6 + 10;
 14 const ll mod =  1e9 + 7;
 15 
 16 int a[maxn];
 17 
 18 struct node {
 19     int l,r,id;
 20 };
 21 
 22 bool cmp(node x,node y) {
 23     if(x.id != y.id) return x.id < y.id;
 24     return x.l > y.l;
 25 }
 26 
 27 vector<node>vec[maxm];
 28 vector<pii>now,nex;
 29 
 30 ll sum[maxn<<2],ans[maxn];
 31 int lazy[maxn<<2];
 32 
 33 inline void init(int rt,int l,int r) {
 34     if(!sum[rt] && !lazy[rt]) return ;
 35     sum[rt] = lazy[rt] = 0;
 36     if(l == r) return ;
 37     int mid = (l + r) >> 1;
 38     init(rt<<1,l,mid);
 39     init(rt<<1|1,mid + 1,r);
 40 }
 41 
 42 inline void pushdown(int rt,int l,int r) {
 43     if(lazy[rt]) {
 44         int mid = (l + r) >> 1;
 45         lazy[rt<<1] += lazy[rt];
 46         lazy[rt<<1|1] += lazy[rt];
 47         sum[rt<<1] += 1ll * (mid - l + 1) * lazy[rt];
 48         sum[rt<<1|1] += 1ll * (r - mid) * lazy[rt];
 49         lazy[rt] = 0;
 50     }
 51 }
 52 
 53 inline void update(int rt,int l,int r,int ql,int qr) {
 54     if(ql <= l && qr >= r) {
 55         lazy[rt]++;
 56         sum[rt] += (ll)(r - l + 1);
 57         return ;
 58     }
 59     pushdown(rt,l,r);
 60     int mid = (l + r) >> 1;
 61     if(qr <= mid) update(rt<<1,l,mid,ql,qr);
 62     else if(ql > mid) update(rt<<1|1,mid + 1,r,ql,qr);
 63     else {
 64         update(rt<<1,l,mid,ql,mid);
 65         update(rt<<1|1,mid + 1,r,mid + 1,qr);
 66     }
 67     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
 68 }
 69 
 70 inline ll query(int rt,int l,int r,int ql,int qr) {
 71     if(ql <= l && qr >= r) return sum[rt];
 72     pushdown(rt,l,r);
 73     int mid = (l + r) >> 1;
 74     if(qr <= mid) return query(rt<<1,l,mid,ql,qr);
 75     else if(ql > mid) return query(rt<<1|1,mid + 1,r,ql,qr);
 76     else return query(rt<<1,l,mid,ql,mid) + query(rt<<1|1,mid + 1,r,mid + 1,qr);
 77 }
 78 
 79 int main() {
 80 #ifdef local
 81     freopen("data.txt", "r", stdin);
 82 //    freopen("data.txt", "w", stdout);
 83 #else
 84     freopen("gcdrng.in", "r", stdin);
 85 #endif
 86     int t;
 87     scanf("%d",&t);
 88     while(t--) {
 89         int n,q;
 90         scanf("%d%d",&n,&q);
 91         for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
 92         for(int i = 1; i <= q; i++) {
 93             int l,r,d;
 94             scanf("%d%d%d",&l,&r,&d);
 95             vec[d].push_back({-i,l,r});
 96         }
 97         nex.clear();
 98         for(int i = 1; i <= n; i++) {
 99             now.clear();
100             now.push_back(mp(a[i],1));
101             for(int j = 0; j < nex.size(); j++) {
102                 pii p = nex[j];
103                 int g = __gcd(now[now.size() - 1].first,p.first);
104                 if(g == now[now.size() - 1].first) now[now.size() - 1].second += p.second;
105                 else now.push_back(mp(g,p.second));
106             }
107             int r = i;
108             for(int j = 0; j < now.size(); j++) {
109                 pii p = now[j];
110                 vec[p.first].push_back({r - p.second + 1,r,i});
111                 r -= p.second;
112             }
113             nex = now;
114         }
115         for(int i = 1; i <= 1e6; i++) {
116             init(1,1,n);
117             sort(vec[i].begin(),vec[i].end(),cmp);
118             for(int j = 0; j < vec[i].size(); j++) {
119                 node p = vec[i][j];
120                 if(p.l > 0) update(1,1,n,p.l,p.r);
121                 else ans[-p.l] = query(1,1,n,p.r,p.id);
122             }
123             vec[i].clear();
124         }
125         for(int i = 1; i <= q; i++) printf("%lld
",ans[i]);
126     }
127     return 0;
128 }

 

以上是关于2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (线段树+GCD)的主要内容,如果未能解决你的问题,请参考以下文章

ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syr

ACM International Collegiate Programming Contest, JUST Collegiate Programming Contest (2018)

German Collegiate Programming Contest 2018?

通过 XSLT 转换 XML 文件将数字转换为罗马数字

2018 German Collegiate Programming Contest (GCPC 18)

2018 ACM-ICPC, Syrian Collegiate Programming Contest