HDU 5381 The sum of gcd (莫队 + 二分 + 区间GCD特性)
2018-03-14 10:32
369 查看
/** 题意:.... 思路: 固定一个端点(值为k),那么这个端点属于的所有区间的不同的gcd最多只有logk中,因为gcd 整除 k, 从大到小排序去重后 后一个数至少除以2,所以不同的GCD最多只有logk个,那么找出这个端点往左和往右当GCD为g时能扩展到多远,这个二分即可,区间 的gcd用ST表预处理出来,之后找出关系式后莫队算法就可以了 */ #include<bits/stdc++.h> typedef long long ll; const int maxn = 1e4 + 10; using namespace std; int n, m, T, kase = 1; int a[maxn], Q, block[maxn]; int st[maxn][15]; ll ans[maxn]; struct qry { int b, l, r, id; qry() {} qry(int b, int l, int r, int id) : b(b), l(l), r(r), id(id) {} bool operator < (qry p) const { if(b != p.b) return b < p.b; return r < p.r; } } q[maxn]; struct P { int l, r, g; P() {} P(int l, int r, int g) : l(l), r(r), g(g) {} }; vector<P> gl[maxn], gr[maxn]; int gcd(int x, int y) { return y ? gcd(y, x % y) : x; } void init() { for(int i = 1; (1 << i) <= n; i++) { int sz = (1 << (i - 1)), s = (1 << i); for(int x = 1; x < n; x++) { if(x + s - 1 > n) break; int j = x + sz; st[x][i] = gcd(st[x][i - 1], st[j][i - 1]); } } } int query(int l, int r, int val) { int tot = (r - l + 1), i = 0; while((1 << i) <= tot) i++; i--; for( ; i >= 0; i--) if(l + (1 << i) - 1 <= r) { int x = st[l][i]; l = l + (1 << i); int y = x / val; if(x - val * y) return 0; } return 1; } void init_block(int siz) { int num = 1, cnt = 1; while(num < n + 5) { for(int i = 0; i < siz && num < n + 5; i++) block[num++] = cnt; cnt++; } } ll calculate_sum(ll i, ll l, ll r) { ll sum = 0; for(ll x = 0; x < gl[i].size(); x++) { P info = gl[i][x]; ll ans = info.g; ll L = max(l, (ll)info.l), R = min(r, (ll)info.r); if(L > R) break; sum += ans * (R - L + 1); } for(ll x = 0; x < gr[i].size(); x++) { P info = gr[i][x]; ll ans = info.g; ll L = max(l, (ll)info.l), R = min(r, (ll)info.r); if(L > R) break; sum += ans * (R - L + 1); } return sum - a[i]; } void solve(ll &las_ans, ll lasl, ll lasr, ll nowl, ll nowr, int id) { while(lasl < nowl) { las_ans -= calculate_sum(lasl, lasl, lasr); lasl++; } while(lasl > nowl) { lasl--; las_ans += calculate_sum(lasl, lasl, lasr); } while(lasr < nowr) { lasr++; las_ans += calculate_sum(lasr, lasl, lasr); } while(lasr > nowr) { las_ans -= calculate_sum(lasr, lasl, lasr); lasr--; } ans[id] = las_ans; } inline bool scan_d(int &num) { char in;bool IsN=false; in=getchar(); if(in==EOF) return false; while(in!='-'&&(in<'0'||in>'9')) in=getchar(); if(in=='-'){ IsN=true;num=0;} else num=in-'0'; while(in=getchar(),in>='0'&&in<='9'){ num*=10,num+=in-'0'; 4000 } if(IsN) num=-num; return true; } int main() { scan_d(T); while(T--) { scan_d(n); int bck = sqrt(n) + 1; for(int i = 1; i <= n; i++) { scan_d(a[i]); block[i] = i / bck; st[i][0] = a[i]; gl[i].clear(); gr[i].clear(); } init(); for(int i = 1; i <= n; i++) { int lasg = a[i], from = i; while(from) { ///log * log * log ??? int l = 1, r = from, g = gcd(lasg, a[from]); while(l < r) { ///log int mid = (l + r) >> 1; int flag = query(mid, from, g); if(!flag) l = mid + 1; else r = mid; } gl[i].push_back(P(l, from, g)); from = l - 1; lasg = g; } from = i; lasg = a[i]; while(from < n + 1) { int l = from, r = n + 1, g = gcd(lasg, a[from]); while(l < r) { int mid = (l + r) >> 1; int flag = query(from, mid, g); if(flag) l = mid + 1; else r = mid; } gr[i].push_back(P(from, r - 1, g)); from = r; lasg = g; } } scan_d(Q); for(int i = 1; i <= Q; i++) { int l, r; scan_d(l); scan_d(r); q[i] = qry(block[l], l, r, i); } sort(q + 1, q + 1 + Q); q[0] = qry(0, 1, 1, 0); ll nowl, nowr, lasl = 1, lasr = 1, las_ans = a[1]; for(int i = 1; i <= Q; i++) { nowl = (ll)q[i].l; nowr = (ll)q[i].r; solve(las_ans, lasl, lasr, nowl, nowr, q[i].id); lasl = nowl; lasr = nowr; } for(int i = 1; i <= Q; i++) printf("%lld\n", ans[i]); } return 0; }
相关文章推荐
- HDU 5381(The sum of gcd-莫队算法解决区间段gcd的和)
- 莫队算法 区间Gcd Hdu 5381
- Hdu 5726 GCD【思维+二分+区间Gcd】好题!
- HDU 5381 The sum of gcd 询问区间内所有子区间的GCD和 [暴力法]
- HDU 5726 求gcd=k的区间的个数 (二分+RMQ)
- hdu 5381 The sum of gcd (线段树x树状数组x区间和维护进阶x离线处理)
- HDU 5726 GCD (rmq+二分 or 线段树 维护区间gcd)
- hdu 5381 The sum of gcd(线段树等差数列区间修改+单点查询)
- 【HDU 5381】 The sum of gcd (子区间的xx和,离线)
- HDU 5381 The sum of gcd 询问区间内所有子区间的GCD和 [莫队算法]
- hdu 5726 区间gcd RMQ+二分 || 暴力枚举
- HDU 4343 多查询求区间内的最大不相交区间个数-思维&贪心-卡时间&二分&剪枝
- hdu-5700 区间交(二分+树状数组)
- HDU 4676 Sum Of Gcd(欧拉函数求区间gcd之和+分块算法)
- HDU 4417 (二分 + 区间第k大)
- Hdu-5726 GCD (二分 + RMQ)
- RMQ + 二分_______GCD(hdu 5726 2016多校第一场)
- HDU 5869 区间不同GCD的个数
- HDU 5726 GCD 【区间GCD + 暴力预处理】
- HDU 5726 GCD 区间GCD=k的个数