2013 Multi-University Training Contest 8
HDU-4676 Sum Of Gcd
题意:给定一个1-N的全排列序列,N<=20000,有Q组询问,Q<=20000,每组询问给出左右区间[l, r],问区间内的任意两个数的gcd之和为多少?
分析:早几场多校做过一道题目是问任意区间的gcd最大值为多少。使用的离线加线段树的方法。这题的解题就需要一些数论知识知识了。对于任意一段区间,任意两个数的gcd值一定会是区间内某个数的因子,因此我们从因子出发,通过得到该区间内所有数的所有因子分别出现的次数,那么就有线索来求最终的答案了。例如区间内数为[3, 6, 9, 36, 72],那么找到因子3,其出现的次数为5次,记为<3, 5>同样的有<2, 3>, <4, 2>, <6, 3>, <8,1>, <9, 3>, <18, 2>, <36, 2>, <72, 1>,如果此时以为对任意一个因子的个数 t ,取C(2, t)就错了,且不说因子个数只有一个的数不能够成为公因子(例如<8, 1>, <72, 1>等),就算成为公因子也未必是最大的公因子(例如<18, 2>等)。实际在统计的过程中不采用组合数的方式,而采用观察单个数带来的影响的方式。考虑到已知数 A 的因子 d 在区间其他数中出现了 k 次,那么如果 d 是所有gcd(A, other)的值时,那么最终的结果加上k*d,但这是不一定的,且 d 的因子肯定也是 A 的因子,当枚举到 d 的因子 d' 时显然就不能够加了。当务之急是找到某种方式使得所有的因子都被统计又不会是结果增多,没错,容斥。不过这里的容斥有点不太一样,而是给每个因子一个容斥因子f(d)使得 k*f(d) + k*f(d') + k*f(d'') + ... + k*f(1) = k*d,这样如果 d 出现 k 次,那么其因子的因子等等就也会出现 k 次,而将他们都统计起来的最终结果就是等效于 k*d。可以证明f(d) = phi(d),后者为欧拉函数。其实也即是 n = sum{phi(d) , d|n}。有了这些结论之后,把20000之内的数全部求出因子,然后对询问区间做一个起点以sqrt(n)分块的排序(不这样会TLE)动态的更新到每一个区间,每次讲边界的数进行更新,求出答案。
一段关于分块算法时间复杂度的分析:http://blog.csdn.net/yang_7_46/article/details/9618637
时间复杂度分析:
排完序后,对于相邻的两个查询,left值之间的差最大为sqrt(n),则相邻两个查询左端点移动的次数<=sqrt(n),总共有t个查询,则复杂度为O(t*sqrt(n))。又对于相同块内的查询,right端点单调上升,每一块所有操作,右端点最多移动O(n)次,总块数位sqrt(n),则复杂度为O(sqrt(n)*n)。right和left的复杂度是独立的,因此总的时间复杂度为O(t*sqrt(n) + n*sqrt(n))。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std; typedef long long LL;
const int N = ;
int M;
struct Node{
int l, r, No;
bool operator < (const Node &t) const {
int a = l/M, b = t.l/M; // 计算出端点落在以sqrt(n)分块的哪一块
if (a != b) return a < b;
return r < t.r;
}
};
int n, seq[N];
Node q[N];
int phi[N];
vector<int>v[N];
int num[N];
LL ans[N]; void prepare() {
for (int i = ; i < N; ++i) {
for (int j = i; j < N; j += i) {
v[j].push_back(i);
}
} // 处理每个数的因子
for (int i = ; i < N; ++i) phi[i] = i;
for (int i = ; i < N; ++i) {
if (phi[i] == i) {// 说明 i 是一个质数
for (int j = i; j < N; j += i) {
phi[j] = phi[j]/i*(i-);
}
}
}
} LL modify(int x, int f) {
LL ret = ;
for (int i = ; i < (int)v[x].size(); ++i) {
const int &d = v[x][i];
if (f == -) ret += phi[d] * (--num[d]);
else ret += phi[d] * (num[d]++);
}
return ret;
} void solve() {
int Q;
scanf("%d", &Q);
memset(num, , sizeof (num));
for (int i = ; i <= Q; ++i) {
q[i].No = i;
scanf("%d %d", &q[i].l, &q[i].r);
}
M = (int)sqrt(n);
sort(q+, q++Q);
LL ret = ;
int lb = q[].l, rb = q[].r; // 首先处理出第一个边界
for (int i = lb; i <= rb; ++i) {
ret += modify(seq[i], +);
}
ans[q[].No] = ret;
for (int i = ; i <= Q; ++i) {
int L = q[i].l, R = q[i].r;
while (lb > L) ret += modify(seq[--lb], +); // 首先进行区间放大
while (rb < R) ret += modify(seq[++rb], +);
while (lb < L) ret -= modify(seq[lb++], -);
while (rb > R) ret -= modify(seq[rb--], -);
ans[q[i].No] = ret;
}
for (int i = ; i <= Q; ++i) {
printf("%I64d\n", ans[i]);
}
} int main() {
prepare();
int T, ca = ;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = ; i <= n; ++i) {
scanf("%d", &seq[i]);
}
printf("Case #%d:\n", ++ca);
solve();
}
return ;
}
2013 Multi-University Training Contest 8的更多相关文章
- Integer Partition(hdu4658)2013 Multi-University Training Contest 6 整数拆分二
Integer Partition Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- Partition(hdu4651)2013 Multi-University Training Contest 5
Partition Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków
ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...
- Partition(hdu4651)2013 Multi-University Training Contest 5----(整数拆分一)
Partition Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- JSU 2013 Summer Individual Ranking Contest - 5
JSU 2013 Summer Individual Ranking Contest - 5 密码:本套题选题权归JSU所有,需要密码请联系(http://blog.csdn.net/yew1eb). ...
- HDU4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- HDU 2018 Multi-University Training Contest 3 Problem A. Ascending Rating 【单调队列优化】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6319 Problem A. Ascending Rating Time Limit: 10000/500 ...
- 2015 Multi-University Training Contest 8 hdu 5390 tree
tree Time Limit: 8000ms Memory Limit: 262144KB This problem will be judged on HDU. Original ID: 5390 ...
- hdu 4946 2014 Multi-University Training Contest 8
Area of Mushroom Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 2016 Multi-University Training Contest 2 D. Differencia
Differencia Time Limit: 10000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot ...
随机推荐
- jQuery 文档操作方法(w3school)
这些方法对于 XML 文档和 HTML 文档均是适用的,除了:html(). 方法 描述 addClass() 向匹配的元素添加指定的类名. after() 在匹配的元素之后插入内容. append( ...
- Linux CentOS 6.5 yum安装MongoDB的操作
安装MongoDB的方法有很多种,可以源代码安装,在CentOS也可以用yum源安装的方法.由于MongoDB更新得比较快,我比较喜欢用yum源安装的方法.64位CentOS下的安装步骤如下: 1.准 ...
- python中split函数的使用
最近学习python,对split函数做了下总结,内容如下:
- java 数组基本操作(一维)
1.数组的声明: 数组类型 数组名[] 2.数组的表示方法 想使用数组中的值,可以使用索引来实现,数组是从0开始的,使用时格式为:数组名[i],比如 a[1],代表第二个值 在数组中要使用数组的长度 ...
- 20150618_Andriod _set Dialog_弹出式菜单
参考地址: http://blog.csdn.net/zhyl8157121/article/details/8169172 http://blog.csdn.ne ...
- 使用oracle写if判断
DECLARE L_X INT; BEGIN SELECT COUNT(*) INTO L_X FROM SYSTEMROLEFUNCTION WHERE ROLEID = '1'; IF L_X & ...
- zend studio 12.0 怎么汉化?
网上搜索到的答案在:http://zhidao.baidu.com/link?url=OUGXDr0H28ad0UYSCUQ27BziJnymTcfWCmNAmzSRorOe3ZDSRhRXY0QoE ...
- CountDownLatch的原理学习
转载:http://blog.csdn.net/yanyan19880509/article/details/52349056 前言 前面介绍了ReentrantLock,又叫排他锁,本篇主要通过Co ...
- hibernate有关联关系删除子表时可能会报错,可以用个clear避免错误
//清除子表数据 public SalesSet removeSalesSetDistributor(SalesSet salesSet ){ List<SalesSetDistributor& ...
- 2016 Al-Baath University Training Camp Contest-1 E
Description ACM-SCPC-2017 is approaching every university is trying to do its best in order to be th ...