题目来源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. vue 判断是否登录,未登录跳转到登录页

    网页一进入判断是否登录,未登录跳转到登录页面 router.js export default new Router({ routes: [ { path: '/', name: 'HelloWorl ...

  2. PHP面向对象编程(1)基础

    一.面向对象OOP(Oriented Object Programming) 面向过程的编程 将要实现的功能描述为一个从一开始到结束的连续的“步骤(过程)”. 一次逐步完成这些步骤.如果步骤比较大,又 ...

  3. 动态规划:HDU-2542-0-1背包问题:饭卡

    解题心得: 这题就是一个简单的0-1背包问题,只不过加了一系列的限制.可以想办法消去限制,直接转换成0-1背包问题的模板形式. 需要注意的几个点:首先对于剩余的5元钱的处理可以直接在总的钱数上将5减去 ...

  4. [Poj3133]Manhattan Wiring (插头DP)

    Description 题目大意:给你个N x M(1≤N, M≤9)的矩阵,0表示空地,1表示墙壁,2和3表示两对关键点.现在要求在两对关键点之间建立两条路径,其中两条路径不可相交或者自交(就是重复 ...

  5. Spring.Net初认识——竹子整理

    留个脚印,过两天总结. 看到知乎上有人对于DI|IOC 的解释,满不错,收藏下先 作者:OneNoodle链接:http://www.zhihu.com/question/23277575/answe ...

  6. Android开发——用户在屏幕上的手势识别

    个定点决定.四个属性分别为left(1),top(2),right(3),bottom(4). 数字为图上标出的距离.显然这四个属性是相对于父容器来定的,均可以通过get()方法获取. 因此很容易得出 ...

  7. 扩展MarkDown表格

    一直不知道表格中的:是什么意思,看了GcsSloop的这篇文章后恍然大悟,做下记录. 原文链接 第二行分割线部分可以使用 : 来控制内容状态 MarkDown : | 默认 | 靠右 | 居中 | 靠 ...

  8. NOI p 2017 TG游记

    嗨小朋友们大家好 还记得我是谁吗 对了我就是为iot配音的演员 弹鸡鸡 今天呐我特别的要向长沙市的oier们 洛谷的oier们 还有cnblogs的oier们问声好 为什么呢 因为我们在2017年11 ...

  9. Python框架之Django学习笔记(十)

    又是一周周末,如约学习Django框架.在上一次,介绍了MVC开发模式以及Django自己的MVT开发模式,此次,就从数据处理层Model谈起. 数据库配置 首先,我们需要做些初始配置:我们需要告诉D ...

  10. java setVisible顺序不同导致窗体内容不显示问题

    今天学习JAVA编写窗体的时候,先写了setVisible(true);然后才去创建的各种控件以及设置大小.位置等 结果运行后只显示空白的窗体,必须最小化再最大化或点击一下边框,才显示窗体内容(即必须 ...