还是想不到,真的觉得难,思路太巧妙

题意:给你一串数和一些区间,对于每个区间求出区间内每段连续值的不同gcd个数(该区间任一点可做起点,此点及之后的点都可做终点)

首先我们可以知道每次添加一个值时gcd要么不变要么减小,并且减小的幅度很大,就是说固定右端点时最多只能有(log2 a)个不同的gcd,而且我们知道gcd(gcd(a,b),c)=gcd(a,gcd(b,c)),所以我们可以使用n*(log2 n)的时间预处理出每个固定右端点的不同gcd的值和位置。解法就是从左到右,每次只需要使用上一次的不同gcd的值和位置。

离线处理每个询问,按照区间右端点从小到大排序,把预处理的每个gcd依次加入树状数组中,这样到一个询问的右端点时就区间查询不同gcd的个数(只需要使用左端点的位置)。树状数组在每种gcd最右一个左端点的位置(贪心想法)存这儿gcd的个数,但可能这个gcd之前出现过,因此我们可以再开一个数组存每种gcd的位置(保证每种gcd在最右边的位置)

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Mod=1e9+;
const int Max=;
struct node
{
int mpos,gcd;
} dp[Max][]; //预处理
struct nide
{
int lef,rig,mpos;
} qes[Max];
int bit[Max],mpos[Max*];//树状数组处理此位置元素个数 某个gcd的位置(这时的最靠右)
int num[Max],ans[Max],n;
void Swap(int &a,int &b)
{
a^=b;
b^=a;
a^=b;
return;
}
int Gcd(int a,int b)// a、b 均为偶数, gcd(a,b) = 2 * gcd(a/2, b/2)
{
if(a<b)
Swap(a,b);
int c=; //a为偶数,b为奇数, gcd(a,b) = gcd(a/2 , b)
while(a-b) //a为奇数,b为偶数,gcd(a,b) = gcd(a, b/2)
{
if(a&) //a、b均为奇数, gcd(a,b) = gcd((a-b)/2, b)
{
if(b&)
{
if(a>b) a=(a-b)>>;
else b=(b-a)>>;
}
else b>>=;
}
else
{
if(b&) a>>=;
else c<<=,a>>=,b>>=;
}
}
return c*a;
}
int cntt[Max];
void Init()//预处理固定右端点时左边的g不通gcd
{
int tmp;
cntt[]=;
for(int i=; i<=n; ++i) //固定右端点i
{
cntt[i]=;
dp[i][].gcd=num[i];
dp[i][].mpos=i;
for(int j=; j<=cntt[i-]; ++j)
{
tmp=Gcd(dp[i][cntt[i]].gcd,dp[i-][j].gcd);
if(tmp!=dp[i][cntt[i]].gcd)//与每个右端点形成不同的gcd的位置要尽量靠右
{
dp[i][++cntt[i]].gcd=tmp;
dp[i][cntt[i]].mpos=dp[i-][j].mpos;
}
}
}
return;
}
bool cmp(struct nide p1,struct nide p2)//排序右端点才可以统计
{
return p1.rig<p2.rig;
}
int lowbit(int x)
{
return x&(-x);
}
void Add(int x,int y)
{
while(x<=n)
{
bit[x]+=y;
x+=lowbit(x);
}
return;
}
int Sum(int x)
{
int sum=;
while(x)
{
sum+=bit[x];
x-=lowbit(x);
}
return sum;
}
void Solve(int q)
{
memset(bit,,sizeof(bit));
memset(mpos,,sizeof(mpos));
int k=,sum=;
for(int i=; i<=n; ++i) //枚举右端点
{
for(int j=; j<=cntt[i]; ++j)
{
if(!mpos[dp[i][j].gcd])
{
sum++;
Add(dp[i][j].mpos,);
mpos[dp[i][j].gcd]=dp[i][j].mpos;
}
else if(mpos[dp[i][j].gcd]<dp[i][j].mpos)//保证最右位置
{
Add(mpos[dp[i][j].gcd],-);
Add(dp[i][j].mpos,);
mpos[dp[i][j].gcd]=dp[i][j].mpos;
}
}
while(k<=q&&qes[k].rig==i)
{
ans[qes[k].mpos]=sum-Sum(qes[k].lef-);//计算[lef,rig]的个数
++k;
}
}
return;
}
int main()
{
int q;
while(~scanf("%d %d",&n,&q))
{
for(int i=; i<=n; ++i)
scanf("%d",&num[i]);
Init();
for(int i=; i<=q; ++i)
{
scanf("%d %d",&qes[i].lef,&qes[i].rig);
qes[i].mpos=i;
}
sort(qes+,qes++q,cmp);
Solve(q);
for(int i=; i<=q; ++i)
printf("%d\n",ans[i]);
}
return ;
}

HDU 5869 Different GCD Subarray Query(2016大连网络赛 B 树状数组+技巧)的更多相关文章

  1. query 2019徐州网络赛(树状数组)

    query \[ Time Limit: 2000 ms \quad Memory Limit: 262144 kB \] 题意 补题才发现比赛的时候读了一个假题意.... 给出长度为 \(n\) 的 ...

  2. HDU 5869 Different GCD Subarray Query rmq+离线+数状数组

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5869 Different GCD Subarray Query Time Limit: 6000/3 ...

  3. hdu 5869 Different GCD Subarray Query BIT+GCD 2016ICPC 大连网络赛

    Different GCD Subarray Query Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K ( ...

  4. HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gc ...

  5. HDU 5869 Different GCD Subarray Query 树状数组 + 一些数学背景

    http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:给定一个数组,然后给出若干个询问,询问[L, R]中,有多少个子数组的gcd是不同的. 就是[L, ...

  6. HDU 5869 Different GCD Subarray Query 离线+树状数组

    Different GCD Subarray Query Problem Description   This is a simple problem. The teacher gives Bob a ...

  7. HDU 5869 Different GCD Subarray Query 树状数组+离线

    Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...

  8. HDU 5869 Different GCD Subarray Query

    离线操作,树状数组,$RMQ$. 这个题的本质和$HDU$ $3333$是一样的,$HDU$ $3333$要求计算区间内不同的数字有几个. 这题稍微变了一下,相当于原来扫描到$i$的之后是更新$a[i ...

  9. 【刷题】HDU 5869 Different GCD Subarray Query

    Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...

随机推荐

  1. 利用Bootstrap简单实现一个文件上传进度条

    © 版权声明:本文为博主原创文章,转载请注明出处 说明: 1. 使用commons-fileupload.jar实现文件上传及进度监听 2. 使用bootstrap的进度条进行页面显示 3. 因为进度 ...

  2. 官方教程Stealth学习笔记(一)

    今天開始要更新官方教程stealth的学习笔记啦, 我将会记录和解说一个小游戏基本的流程和关键地方的技巧. 我会依照官方教程的顺序来更新.                                ...

  3. 怎样新建Quartusproject—FPGA新手教程

    这一章我们来实现第一个FPGAproject-LED流水灯.我们将通过流水灯例程向大家介绍一次完整的FPGA开发流程,从新建project,代码设计,综合实现.管脚约束,下载FPGA程序. 掌握本章内 ...

  4. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. win10--vs2015--libjpeg--64位库的编译过程记录

    win10--vs2015--libjpeg--64位库的编译过程记录 1. 下载源代码:   http://libjpeg.sourceforge.net/    或者  http://www.ij ...

  6. HTML5 2D平台游戏开发#9蓄力技

    在很多动作游戏中,玩家操控的角色可以施放出比普通攻击更强力的蓄力技,一般操作为按住攻击键一段时间然后松开,具体效果像下面这张图: 要实现这个操作首先要记录下按键被按住的时间,初始是0: this.sa ...

  7. 出现windows启动服务失败(无法从命令行或调试器启动,需要安装InstallUtil.exe)的解决办法

    两种方法1 从命令行安装2 选择项目-视图-自定义操作   然后将 安装,提交,回滚,卸载分别加入自定义操作,注意InstallClass属性为true

  8. C++11并发学习之三:线程同步(转载)

    C++11并发学习之三:线程同步 1.<mutex> 头文件介绍 Mutex又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文 ...

  9. 多媒体开发之---H264 RTSP交互过程

    OPTIONS rtsp://192.168.1.154:8557/h264 RTSP/1.0 CSeq: 1 User-Agent: VLC media player (LIVE555 Stream ...

  10. linux下nginx php配置redis

      之前一直遇到,Module compiled with module API=20090626这个坑问题!!! NOTICE: PHP message: PHP Warning: PHP Star ...