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 ...
随机推荐
- SQLServer学习笔记<>sql的范围内查找,sql数据类型,字符串处理函数
sql的范围内查找 (1)between.....and用法 通常情况下我们查找一个在某固定区域内的所有记录,可以采用>=,<=来写sql语句,例如:查找订单价格在1000到2000之间的 ...
- Android实现推送方式解决方案(转)
本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...
- hdu4932 Miaomiao's Geometry
这是一道搜索题,我们很容易得到目标值的上下界,然后就只能枚举了. 就是将x轴上的点排序之后从左到右依次考察每个点,每个点要么在线段的左端点,要么在线段的右端点. 点编号从0到n-1,从编号为1的点开始 ...
- Who's in the Middle 分类: POJ 2015-06-12 19:45 11人阅读 评论(0) 收藏
Who's in the Middle Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 34155 Accepted: 1 ...
- win10 + VS2015 + EF6 + MySQL
前置配置 在下面的网址去安装最新版的 (Connector/Net http://dev.mysql.com/downloads/connector/net/#downloads) 然后安装 MySQ ...
- torch基本操作
1.在terminal中th进入troch,th+文件名.lua运行文件.进入torch之后,dofile+"文件名.lua"运行文件
- hdu 1999 不可摸数 水题。
不可摸数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- 精通D3.js学习笔记(2)比例尺和坐标
1.线性比例尺 d3.scale.linear() 创建一个线性比例尺 .domain([0,500]) 定义域 .range([0,1000]) 值域 l ...
- Java 关键字final
在程序设计中,我们有时可能希望某些数据是不能够改变的,这个时候final就有用武之地了.final是java的关键字,它所表示的是"这部分是无法修改的".不想被改变的原因有两个:效 ...
- COM技术の接口
什么是接口 DLL的接口可以理解为其导出的那些函数,C++类的接口则是该类的一个成员函数集. 对于COM来说,接口是一个包含一个函数指针数组的内存结构,每一个数组元素包含的是一个由组件所实现的函数的地 ...