1. 程式人生 > >2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (線段樹+GCD)

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\n",ans[i]); 126 } 127 return 0; 128 }