[HDU 5042 GCD pair] 离线+按GCD相同分段
来源:互联网 发布:苹果美版网络锁查询 编辑:程序博客网 时间:2024/06/06 17:38
题目
http://acm.hdu.edu.cn/showproblem.php?pid=5042
分析
离线+按GCD相同分段
与ZOJ 3800思路很像,想法都是按照gcd相等的一段分段,因为gcd的性质,不会超过logN段
然后处理出所有的gcd和出现的次数,排序,再把所有询问离线,select挂到对应的gcd上,rank挂到对应的左段点上
然后从后往前枚举,再用上面的方法统计一次即可
时间复杂度O(Nlog^2N)
代码
/************************************************** * Problem: HDU 5042 * Author: clavichord93 * State: Accepted **************************************************/#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <vector>#include <algorithm>#include <cassert>#include <functional>using namespace std;typedef long long ll;const int MAX_N = 100005;int n, cntQuery;int a[MAX_N];char op[10];vector< pair<ll, int> > selects[MAX_N];vector< pair<int, int> > queries[MAX_N];int cntGcd;int gcd[MAX_N * 20];int rank[MAX_N];ll cnt[MAX_N];ll tot[MAX_N];int stack[MAX_N];int entry[MAX_N];int _stack[MAX_N];int _entry[MAX_N];int curSelect[MAX_N];pair<ll, ll> ans[MAX_N];int main() { #ifdef LOCAL_JUDGE freopen("in.txt", "r", stdin); #endif int T; scanf("%d", &T); for (int cas = 1; cas <= T; cas++) { memset(cnt, 0, sizeof(cnt)); memset(tot, 0, sizeof(tot)); for (int i = 0; i <= 100000; i++) { selects[i].clear(); queries[i].clear(); } scanf("%d %d", &n, &cntQuery); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } cntGcd = 0; { int top = 0; stack[0] = 0; entry[0] = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= top; j++) { stack[j] = __gcd(stack[j], a[i]); } int _top = 0; for (int j = 1; j <= top; j++) { if (stack[j] != stack[j - 1]) { _top++; _stack[_top] = stack[j]; _entry[_top] = entry[j]; } } if (!_top || _stack[_top] != a[i]) { _top++; _stack[_top] = a[i]; _entry[_top] = i; } top = _top; entry[top + 1] = i + 1; for (int j = 1; j <= top; j++) { stack[j] = _stack[j]; entry[j] = _entry[j]; } for (int j = 1; j <= top; j++) { tot[stack[j]] += entry[j + 1] - entry[j]; gcd[++cntGcd] = stack[j]; } } } sort(gcd + 1, gcd + cntGcd + 1); cntGcd = unique(gcd + 1, gcd + cntGcd + 1) - gcd - 1; for (int i = 1; i <= cntGcd; i++) { rank[gcd[i]] = i; } //for (int i = 1; i <= cntGcd; i++) { //printf("%d ", gcd[i]); //} //printf("\n"); for (int i = 1; i <= cntQuery; i++) { scanf("%s", op); if (op[0] == 'S') { ll k1, k2; scanf("%I64d %I64d", &k1, &k2); if (k1 <= cntGcd && k2 <= tot[gcd[k1]]) { selects[gcd[k1]].push_back(make_pair(k2, i)); } } else { int l, r; scanf("%d %d", &l, &r); queries[l].push_back(make_pair(r, i)); } ans[i] = make_pair(-1, -1); } for (int i = 1; i <= n; i++) { sort(queries[i].begin(), queries[i].end()); } for (int i = 1; i <= cntGcd; i++) { int x = gcd[i]; sort(selects[x].begin(), selects[x].end(), greater< pair<ll, int> >()); curSelect[x] = 0; } //for (int i = 1; i <= cntGcd; i++) { //int x = gcd[i]; //for (int j = 0; j < (int)selects[x].size(); j++) { //printf("%I64d ", selects[x][j].first); //} //printf("\n"); //} { int top = 0; stack[0] = 0; entry[0] = n + 1; for (int i = n; i >= 1; i--) { for (int j = 1; j <= top; j++) { stack[j] = __gcd(stack[j], a[i]); } int _top = 0; for (int j = 1; j <= top; j++) { if (stack[j] != stack[j - 1]) { _top++; _stack[_top] = stack[j]; _entry[_top] = entry[j]; } } if (!_top || _stack[_top] != a[i]) { _top++; _stack[_top] = a[i]; _entry[_top] = i; } top = _top; entry[top + 1] = i - 1; for (int j = 1; j <= top; j++) { stack[j] = _stack[j]; entry[j] = _entry[j]; } int sizeRank = queries[i].size(); int cur = 0; for (int j = top; j >= 1; j--) { int x = stack[j]; cnt[x] += entry[j] - entry[j + 1]; { while (cur < sizeRank && queries[i][cur].first <= entry[j]) { ll first = rank[x]; ll second = tot[x] - cnt[x] + queries[i][cur].first - entry[j + 1]; ans[queries[i][cur].second] = make_pair(first, second); cur++; } } { int &cur = curSelect[x]; int size = selects[x].size(); while (cur < size && tot[x] - cnt[x] < selects[x][cur].first) { ll first = i; ll second = entry[j + 1] + selects[x][cur].first - tot[x] + cnt[x]; ans[selects[x][cur].second] = make_pair(first, second); cur++; } } } } } printf("Case #%d:\n", cas); for (int i = 1; i <= cntQuery; i++) { if (ans[i].first == -1) { printf("-1\n"); } else { printf("%I64d %I64d\n", ans[i].first, ans[i].second); } } } return 0;}<strong></strong>
0 0
- [HDU 5042 GCD pair] 离线+按GCD相同分段
- HDU 5042 GCD pair 预处理+二分 分段
- hdu 5042 GCD pair(数论 + 二分)
- HDU 5869 Different GCD Subarray Query(离线+gcd)
- hdu 5726 gcd rmq 求相同gcd的区间数量
- hdu 4630 树状数组+离线操作+GCD
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- gcd(线段树离线处理)——HDU 4630
- HDU 5381 The sum of gcd 离线处理+线段树
- MySQL索引概念以及创建方法
- 南邮离散数学实验1 (简单版) 根据真值求真值表和主范式
- Python的html和xml解析库Beautiful Soup
- 年轻的开发者,请善待你自己
- shell中for循环总结
- [HDU 5042 GCD pair] 离线+按GCD相同分段
- VC++ 6.0点打开按钮出现 “Microsoft (R) Developer Studio 已停止工作”的解决方法
- 云帆教育大数据分享-Flume-0.9.4源码编译及一些编译出错解决方法
- 云凡教育分享-Flume-0.9.4源码编译依赖的thrift插件安装
- Linux中智能小开关rfkill
- Flume-0.9.4配置Hbasesink
- Flume-0.9.4和Hbase-0.96整合(1)
- 云凡教育分享-Flume-0.9.4和Hbase-0.96整合(2)
- NOJ 1098 Rails (stack)