The sum of gcd

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 23    Accepted Submission(s): 4

Problem Description
You have an array A,the
length of A is n

Let f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
 
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

First line has one integers n

Second line has n integers Ai

Third line has one integers Q,the
number of questions

Next there are Q lines,each line has two integers l,r

1≤T≤3

1≤n,Q≤104

1≤ai≤109

1≤l<r≤n
 
Output
For each question,you need to print f(l,r)
 
Sample Input
2
5
1 2 3 4 5
3
1 3
2 3
1 4
4
4 2 6 9
3
1 3
2 4
2 3
 
Sample Output
9
6
16
18
23
10
 
Source

求一个区间内随意子区间的gcd之和。

分析:

对于区间[l,r]求gcd之和的复杂度是nlog(n)的

::

如果处理了[l,r]的结果,那么对于[l,r+1]。能产生的新的子区间为[r-l+1]个。怎样合并?

由于增加r+1,那么[L,r+1],(l<=L<=r)必定都是经过r位置的。知道r与之前每一个位置的gcd。

用num[r+1]与这些gcd值,做gcd得到新的gcd值,就是全部新子区间的gcd结果。对于每一个gcd乘以相应的

区间个数就可以。

当然越往左。gcd就会越小,而且最多出现log个gcd值。把同样的gcd合并就能降低运算量。

然后新增加的数自己能够成为一个区间,增加答案中。

处理的复杂度是nlog的,由于分块了,

长度为n的最多sqrt(n)段,复杂度是nlog(n)*sqrt(n)

在块内。长度是sqrt(n)且最多次计算。全部是qlog(n)*sqrt(n)==================(log(n)是gcd的种类数)

如今处理合并两段了:

由于分成左右两段,例如以下

原序列:1 1 1 2 2  2  4 4 4| 4 4 4 2 2 2 1 1 1 (|是分隔位置)

gcd:1 1 1  2 2 2  4 4 4 | 4 4 4 2 2 2 1 1 1

gcd计算的该点到切割位置的路径的gcd,由于合并肯定是须要经过切割位置的!

显然能够知道gcd的种类仅仅有 log(n)个。对于左边的每一个gcd和右边的每一个gcd做一下gcd函数。然后乘以左边该段

的长度*右边该段的长度。如样例就是

gcd(1,1)*3*3+gcd(1,2)*3*3 + gcd(1,4)*3*3)...........+....

怎样计算得到每一个gcd相应的区间个数呢?

能够知道从分隔线到两边的gcd是递减的。假设g是[l,r]的gcd,那么对于[l-1,r]仅仅要gcd(g,num[l-1])就计算出来了

然后得到的gcd假设与g同样就和并。否则增加一个新值。

复杂度分析:

对于每段,求出全部gcd和个数是o(n)的。

长的一段最多求sqrt(n)次。是n*sqrt(n)的。短的是sqrt(n)*q次

合并时复杂度是q*log(n)*log(n)的,所以是 O(sqrt(n)*n+q*sqrt(n)+q*log(n)*log(n))

接下来看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 20001
#define ll long long int gcd(int a,int b){
if(b == 0) return a;
return gcd(b,a%b);
} ll ans[maxn];
struct Node{
int l,r,id;
};
Node que[maxn]; int length;//分块排序函数
int comp(Node a,Node b){
if(a.l / length == b.l / length)
return a.r < b.r;
return a.l /length < b.l/length;
}
int num[maxn]; struct Point{
int g,num;
Point(int _g=0,int _n=0):g(_g),num(_n){}
};
vector<Point> lgcd;
vector<Point> ltrgcd;
vector<Point> rgcd;
vector<Point> rtlgcd; int main(){
int t,n,q;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0;i < n; i++)
scanf("%d",num+i);
scanf("%d",&q);
for(int i = 0;i < q; i++){
scanf("%d%d",&que[i].l,&que[i].r);
que[i].id = i;
que[i].l--,que[i].r--;
} for(length = 1; length * length < n; length++);
sort(que,que+q,comp);//按快排序,同一个块内r从小到大排序 memset(ans,0,sizeof(ans));
lgcd.clear();
rgcd.clear();
ltrgcd.clear();
rtlgcd.clear(); int RR = -1,kuai = -1,j,k,l,LL;
ll res = 0,resl = 0;
Point a;
for(int i = 0;i < q; i++){ 处理每一个询问
if(kuai != que[i].l/length){//新块。所以长的一段要重头開始处理
kuai = que[i].l/length;
rtlgcd.clear();
rgcd.clear();
RR = kuai*length+length-1;
res = 0;
}
while(RR < que[i].r){
RR++;//处理分隔线到RR的gcd之和。 for( j = 0;j < rgcd.size(); j++){
rgcd[j].g = gcd(rgcd[j].g,num[RR]);
res += (ll)rgcd[j].g*rgcd[j].num;
}
rgcd.push_back(Point(num[RR],1));
res += num[RR];
for(j = 0,k = 1;k<rgcd.size();k++){
if(rgcd[j].g == rgcd[k].g){
rgcd[j].num += rgcd[k].num;
}
else {
j++;
rgcd[j] = rgcd[k];
}
}
while(rgcd.size() > j+1) rgcd.pop_back();//合并同样的gcd
//处理分隔线到每一个RR的gcd个数
if(rtlgcd.size() == 0)
rtlgcd.push_back(Point(num[RR],1));
else {
k = rtlgcd.size()-1;//仅仅需比較最小的那个gcd就可以。即最右边计算得到的gcd
a.g = gcd(rtlgcd[k].g,num[RR]);
a.num = 1;
if(a.g == rtlgcd[k].g)
rtlgcd[k].num++;
else rtlgcd.push_back(a);
}
} LL = kuai*length+length-1;
lgcd.clear();
ltrgcd.clear();
resl = 0;//左边的处理与右边的一样
LL = min(LL,que[i].r);
for(;LL >= que[i].l; LL--){
for(j = 0;j < lgcd.size(); j++){
lgcd[j].g = gcd(lgcd[j].g,num[LL]);
resl += (ll)lgcd[j].g*lgcd[j].num;
}
lgcd.push_back(Point(num[LL],1));
resl += num[LL];
for(j = 0,k=1;k<lgcd.size();k++){
if(lgcd[j].g == lgcd[k].g){
lgcd[j].num += lgcd[k].num;
}
else {
j++;
lgcd[j] = lgcd[k];
}
}
while(lgcd.size() > j+1) lgcd.pop_back(); if(ltrgcd.size() == 0){
ltrgcd.push_back(Point(num[LL],1));
}
else {
k = ltrgcd.size()-1;
a.g = gcd(ltrgcd[k].g,num[LL]);
a.num = 1;
if(a.g == ltrgcd[k].g)
ltrgcd[k].num++;
else ltrgcd.push_back(a);
}
}//合并两个区间
ans[que[i].id] = res + resl;
int id = que[i].id,gg;
for(j = 0;j < ltrgcd.size(); j++){
gg = ltrgcd[j].g;
for(k = 0;k < rtlgcd.size(); k++){
gg = gcd(gg,rtlgcd[k].g);
ans[id] += (ll)gg*ltrgcd[j].num*rtlgcd[k].num;
}
}
}
for(int i = 0;i < q; i++){
printf("%I64d\n",ans[i]);
}
}
return 0;
}

hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法的更多相关文章

  1. hdu 5358 First One 2015多校联合训练赛#6 枚举

    First One Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tota ...

  2. HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)

    pid=5358">HDU 5358 题意: 求∑​i=1​n​​∑​j=i​n​​(⌊log​2​​S(i,j)⌋+1)∗(i+j). 思路: S(i,j) < 10^10 & ...

  3. hdu 5361 2015多校联合训练赛#6 最短路

    In Touch Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total ...

  4. 2015多校联合训练赛 hdu 5308 I Wanna Become A 24-Point Master 2015 Multi-University Training Contest 2 构造题

    I Wanna Become A 24-Point Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 ...

  5. 2015多校联合训练赛hdu 5301 Buildings 2015 Multi-University Training Contest 2 简单题

    Buildings Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tota ...

  6. HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

    pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序 ...

  7. 2015多校联合训练赛 Training Contest 4 1008

    构造题: 比赛的时候只想到:前面一样的数,后面 是类似1,2,3,4,5,6....t这 既是:t+1,t+1...,1,2,3,...t t+1的数目 可能 很多, 题解时YY出一个N 然后对N   ...

  8. hdu 5381 The sum of gcd(线段树+gcd)

    题目链接:hdu 5381 The sum of gcd 将查询离线处理,依照r排序,然后从左向右处理每一个A[i],碰到查询时处理.用线段树维护.每一个节点表示从[l,i]中以l为起始的区间gcd总 ...

  9. hdu 5381 The sum of gcd

    知道对于一个数列,如果以x为左(右)端点,往右走,则最多会有log(a[x])个不同的gcd,并且有递减性 所以会分成log段,每一段的gcd相同 那我们可以预处理出对于每一个位置,以这个位置为左端点 ...

随机推荐

  1. [Android Traffic] 根据网络类型更改下载模式

    转载自: http://blog.csdn.net/kesenhoo/article/details/7396321 Modifying your Download Patterns Based on ...

  2. [转载]Lenovo E431 装Centos7无线驱动安装

    FROM:http://huangyandong.blog.51cto.com/1396940/1613096 查看无线网卡型号 lspci |grep Network    #为BCM43142网卡 ...

  3. 计算机速度GHz等于每秒多少次

    这个是没有对比关系的.需要看处理器的微指令.计算机的GHz指的是CPU的时钟频率,不同的指令需要的时钟个数是不同的,列如,从内存读一个数据,一般需要4个时钟周期,而进行一次8位数的加法运算,一般需要1 ...

  4. 2017.7.12 IDEA热部署(更新jsp或java代码不用重启tomcat即可即时生效)

    选择war explored. 主要在于 On frame deactivation选项配置选择为 Update classes and resourses(当且仅当在Deployment配置页,对应 ...

  5. caffe卷积层代码阅读笔记

    卷积的实现思想: 通过im2col将image转为一个matrix,将卷积操作转为矩阵乘法运算 通过调用GEMM完毕运算操作 以下两个图是我在知乎中发现的,"盗"用一下,确实非常好 ...

  6. Intellij idea远程debug连接tomcat,实现单步调试

    转载:http://blog.csdn.net/boling_cavalry/article/details/73384036 web项目部署到tomcat上之后,有时需要打断点单步调试,如果用的是I ...

  7. java中数组的复制

    数组复制使我们在编程过程中经常要使用到的,在java中数组复制我们大概能够分为两种,一种是引用复制,还有一种就是深度复制(复制后两个数组互不相干). 以下我们就通过測试的方法来具体看看什么是引用复制和 ...

  8. navigationItem的设置和titleView的设置

    设置导航栏中间的标题 self.navigationItem.title = @"title"; 设置导航栏的主题颜色 self.navigationBar.barTintColo ...

  9. Activity启动活动最佳写法

    一,在被启动的Activity中新加一个静态方法public static void actionStart(Context context, String data1, String data2) ...

  10. UVA 617 - Nonstop Travel(数论+暴力枚举)

    题目链接:617 - Nonstop Travel 题意:给定一些红绿灯.如今速度能在30-60km/h之内,求多少个速度满足一路不遇到红灯. 思路:暴力每个速度,去推断可不能够,最后注意下输出格式就 ...