题目来源https://www.nowcoder.com/acm/contest/96/I

解题前们需要先知道几个结论:

首先,gcd是有区单调性的: gcd(L,R)>=gcd(L,R+d)  ,因为每添加一个数,gcd只会变小或者不变。

其次,以L左端点的所有区间的【GCD的种类数】一般不超过15,最多不超过31个,因为gcd每次变小时会除掉当前gcd的一个或多个质因子,所以质因数的个数,决定这个gcd

最多能变小几次,而质因子最多的数就是2^31。

预处理:

在解决问题之前我们先做几个预处理,至于这些预处理有什么用,在解题时会说明。

  • :为了快速查询区间gcd我们需要,用ST表先预处理一下数组,使得我们查询任意区间gcd的复杂下降至只需一个gcd(),即O(log(x)).   因为算gcd要一个log的复杂所以总复杂度,近似为 nlog(n)^2
  • 对于每个L,二分计算区间内每种gcd的起始右端点,比如区间[8,4,4,2] 的区间,以下标1开始的区间gcd有 8,4,2这3种gcd,对应的右端点分别为[1,2,4]。因为计算gcd要一个log,二分一个log,而gcd种类数是期望好像是只比O(n)稍大(我瞎猜,不会证【1】)。所以总复杂度是接近nlog(n)^2

计算:设gcd[L,R]=g,要计算有多少个子区间为,其实就算算对于每个Li,对应Ri至少要多少才能使得gcd[Li,Ri]=g。 而答案为Σ(R+1-Ri)

如果你对每个LI都计算R的话,再快也是O(区间长度的) ,没前途。这有个更优美的求法,其实对于任意的Li和g,对应的Ri我们都在预处理的时候算好了,

但是按Li查询的复杂度太高了,那么为啥不考虑一下按g查询

所以在预处理阶段,我们按g分组,并在每个组内并按Li排序(其实按Ri还是按Li都是一样的,因为组内有类似尺取的区间单调性,这点自己手动模拟一下就知道了),

并预处理Ri的前缀和。  接着查询L,R时,在g的组内二分(如果数据是随机的话,暴力也是行的)一下,L<=Li&&Ri<=R 的 区间,利用RI的前缀和一减就可以得分Σ(R+1-Ri)

将映射g到组id,用hash,可O(1).  平均组长log(n).,最坏组长O(n)  .   查询复杂度是 平均时log(log(n))  最快log(n)

加上预处理,最坏复杂度近似为 O(qlogn+nlog(n)^2)

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
using namespace std;
typedef long long ll;
#define N 280000
int dp[][];
int len[];
int a[];
struct node
{
int l,r;
long long sum;
} p;
vector<node>e[];
map<int,int>mp;
inline int cal(int l,int r)
{
if(l>r)
return -;
int k=len[r-l+];
return __gcd(dp[l][k],dp[r-(<<k)+][k]);
}
inline int findr(int l,int r,int g)
{
int k=len[r-l+],b=l,i;
for(i=<<k; i; i>>=)
{
if(b+i<=r&&cal(l,b+i)>=g)
{
b+=i;
}
}
return b;
}
inline int findl(int l,int r,int g)
{
int k=len[r-l+],b=r,i;
for(i=<<k; i; i>>=)
{
if(b-i>=l&&cal(l,b-i)<=g)
{
b-=i;
}
}
return b;
}
int fl(int g,int x)
{
int l=,r,m,k;
k=mp[g];
r=e[k].size();
while(l+<r)
{
m=(l+r)/;
if(e[k][m].l<x)
{
l=m;
}
else
{
r=m;
}
}
return l;
}
int fr(int g,int x)
{
int l=,r,m,k;
k=mp[g];
r=e[k].size();
while(l+<r)
{
m=(l+r)/;
if(e[k][m].r<=x)
{
l=m;
}
else
{
r=m;
}
}
return l;
}
long long fun(int l,int r,int g)
{
long long ans=;
long long a,b;
a=fl(g,l);;
b=fr(g,r);
int k=mp[g];
ans=(b-a)*(r+)-(e[k][b].sum-e[k][a].sum);
return ans;
}
int main()
{
int n,m,k,l,r,i,j,g,q,t,cas=;
len[]=;
for(i=; i<=; i++)
{
len[i]=len[i/]+;
}
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(dp,,sizeof(dp));
mp.clear();
for(i=; i<=n; i++)
{
scanf("%d",&a[i]);
dp[i][]=a[i];
}
for(j=; j<=len[n]; j++)
{
for(i=; i<=n; i++)
{
dp[i][j]=__gcd(dp[i][j-],dp[i+(<<j-)][j-]);
}
}
int ll;
for(i=; i<=n; i++)
{
g=a[i];
ll=i;
while()
{
if(mp.count(g)==)
{
mp[g]=mp.size();
p.l=;
p.r=;
p.sum=;
e[mp[g]].push_back(p);
}
p.l=i;
ll=findr(i,n,g);
p.r=findl(i,n,g);
e[mp[g]].push_back(p);
if(ll>=n)
break;
g=__gcd(g,a[ll+]);
}
}
for(i=; i<=mp.size(); i++)
{
for(j=; j<e[i].size(); j++)
{
e[i][j].sum=e[i][j-].sum+e[i][j].r;
} }
scanf("%d",&q);
printf("Case #%d:\n",cas++);
while(q--)
{
scanf("%d%d",&l,&r);
g=cal(l,r);
printf("%d %lld\n",g,fun(l,r,g));
} for(i=; i<mp.size(); i++)
{
e[i].clear();
}
}
return ;
}

AC代码

长沙理工校赛I题题解-连续区间的最大公约数的更多相关文章

  1. 牛客-长沙理工校赛C-取手机

    传送门:https://www.nowcoder.com/acm/contest/96/C 参考:http://www.cnblogs.com/Dillonh/p/8835074.html 题意: d ...

  2. 2019年华南理工校赛(春季赛)--I--炒股(简单思维水题)

    水题,想想就过了 题目如下: 链接:https://ac.nowcoder.com/acm/contest/625/I来源:牛客网 攒机一时爽,一直攒机一直爽. 沉迷攒机的胡老师很快就发现,他每天只能 ...

  3. 2019字节跳动冬令营day7娱乐赛19题题解

    啊没去听讲题,也没发纸质题解,电子版题解也没有 为最后几个unsolve自闭了一段时间才全都A掉 3个队友写的我没看的题通过人数蛮多就不管了 题目地址:https://pan.baidu.com/s/ ...

  4. csp-s模拟测试55 联,赛,题题解

    题面:https://www.cnblogs.com/Juve/articles/11610969.html 联: 用线段树维护区间和,要修改成1或0就线段树修改区间和 如果是异或,那么新的区间和就是 ...

  5. 2019山东ACM省赛L题题解(FLOYD传递闭包的变形)

    本题地址 https://cn.vjudge.net/contest/302014#problem/L Median Time Limit: 1 Second      Memory Limit: 6 ...

  6. 18华南理工校赛 K 小马哥的超级盐水

    https://www.nowcoder.com/acm/contest/94/K sum(ai)/sum(bi) = x/y <=> sum(ai*yi-bi*x) = 0 跟这题有点类 ...

  7. 福建工程学院第十四届ACM校赛M题题解 fwt进阶,手推三进制fwt

    第九集,结束亦是开始 题意: 大致意思就是给你n个3进制的数字,让你计算有多少对数字的哈夫曼距离等于i(0<=i<=2^m) 思路: 这个是一个防ak题,做法是要手推公式的fwt 大概就这 ...

  8. 福建工程学院第十四届ACM校赛G题题解

    外传:编剧说了不玩游戏不行 题意: 有n个石堆,我每次只能从某一堆中取偶数个石子,你取奇数个,我先手,先不能操作的人输.问最后谁能赢. 思路: 这个题仔细想想,就发现,取奇数的人有巨大的优势,因为假设 ...

  9. 福建工程学院第十四届ACM校赛B题题解

    第二集,未来的我发量这么捉急的吗 题意: 有n个数,请问有多少对数字(i,j)(1<=i<j<=n),满足(a[i]^a[j])+((a[i]&a[j])<<1) ...

随机推荐

  1. 1- vue django restful framework 打造生鲜超市

    Vue+Django REST framework实战 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支 ...

  2. confirm() 方法用于显示一个带有指定消息和 OK 及取消按钮的对话框。系统自带提示

    W3C地址:::::::   http://www.w3school.com.cn/jsref/met_win_confirm.asp http://www.w3school.com.cn/tiy/t ...

  3. Ubuntu设置代理上网

    代理服务器(Proxy Server)是个人网络和Internet服务商之间的中间代理机构,它负责转发合法的网络信息,对转发进行控制和登记.代理服务器作为连接Internet(广域网)与Intrane ...

  4. [Hdu3507]Print Article(斜率优化)

    Description 题意:给N个数,按顺序全部取走,每次取一段连续的区间,代价为\((S[i]-S[j])^2+M\) 其中M为一个给定的常数,\(S[i]\)为前缀和 \(N\leq 50000 ...

  5. lua table长度解析

    先来看lua table源码长度获取部分(ltable.c) j是数组部分的长度.首先判断数组长度大于0,并且数组最后一个是nil,就用二分法查找,返回长度. 如果t->node是 table的 ...

  6. Go语言之并发编程(一)

    轻量级线程(goroutine) 在编写socket网络程序时,需要提前准备一个线程池为每一个socket的收发包分配一个线程.开发人员需要在线程数量和CPU数量间建立一个对应关系,以保证每个任务能及 ...

  7. Neural Network

    逻辑回归用神经网络节点的方式表示 前面已经介绍过逻辑回归的模型,样本为(x,y) 其中y的值为1或0,假设x有2个特征,则对应关系如下图所示.  实际情况是需要求需要三个参数,因此输入层需要添加一个 ...

  8. Sentry 错误监控

    错误监控:https://sentry.io 支持语言或平台: 

  9. 59、佳博wifi打印机怎么配置

    1.去这里下载配置软件(注意,需要再windows下进行)http://pan.baidu.com/s/1bn1y4FX,并解压安装程序 2.连上wifi打印机的热点,比如说佳博打印机的默认为Gpri ...

  10. C++模板编程-模板基础重点

    模板基础 1.模板参数自动推导,如果是已知的参数类型与个数,这调用模板时可以不写类型. Cout<<max<int>(1,3);可以写为Cout<<max(1,3) ...