HDU 5869 Different GCD Subarray Query(2016大连网络赛 B 树状数组+技巧)
还是想不到,真的觉得难,思路太巧妙
题意:给你一串数和一些区间,对于每个区间求出区间内每段连续值的不同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 树状数组+技巧)的更多相关文章
- query 2019徐州网络赛(树状数组)
query \[ Time Limit: 2000 ms \quad Memory Limit: 262144 kB \] 题意 补题才发现比赛的时候读了一个假题意.... 给出长度为 \(n\) 的 ...
- HDU 5869 Different GCD Subarray Query rmq+离线+数状数组
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5869 Different GCD Subarray Query Time Limit: 6000/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 ( ...
- HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gc ...
- HDU 5869 Different GCD Subarray Query 树状数组 + 一些数学背景
http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:给定一个数组,然后给出若干个询问,询问[L, R]中,有多少个子数组的gcd是不同的. 就是[L, ...
- HDU 5869 Different GCD Subarray Query 离线+树状数组
Different GCD Subarray Query Problem Description This is a simple problem. The teacher gives Bob a ...
- HDU 5869 Different GCD Subarray Query 树状数组+离线
Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...
- HDU 5869 Different GCD Subarray Query
离线操作,树状数组,$RMQ$. 这个题的本质和$HDU$ $3333$是一样的,$HDU$ $3333$要求计算区间内不同的数字有几个. 这题稍微变了一下,相当于原来扫描到$i$的之后是更新$a[i ...
- 【刷题】HDU 5869 Different GCD Subarray Query
Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...
随机推荐
- oracle中的minus数据比对
1.要有唯一索引或者主键作为前提,减少数据冲突的数量,如示例标红的地方: 2.当有in查询的时候,尽量用exists,这样能提高查询效率: create table TF_F_USER_DIFF1 ...
- php7.0 出现 curl_setopt(): Disabling safe uploads is no longer supported in 报错!
项目换成php7.0,进行了测试,使用curl时,出现: curl_setopt(): Disabling safe uploads is no longer supported in xxx.定位到 ...
- 好文章收藏--五分钟理解一致性哈希算法(consistent hashing)
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...
- maven 常用的环境插件
<build> <finalName>yycgproject</finalName> <plugins> <!-- 修改jdk插件 --> ...
- 用代码构造PreferenceScreen
在PreferenceFregment中构造界面,简单省事的方法就是使用findPreference然后在xml里把UI写好.在代码中动态的添加UI内容也是需要的.核心代码是: PreferenceS ...
- StartUML
原著:Stephen Wong 翻译:火猴 http://blog.csdn.net/monkey_d_meng/article/details/5995610 Sta ...
- 解决QT:forward declaration of 'struct Ui::xxx';invalid use of incomplete struct "Ui::Widget" 等莫名奇异错误
今天在进行QT Widget的UI设计时,改了下Widget的对象名,然后在多次成功编译执行后,执行清理,又一次构建,就出现了好多莫名奇异的错误: widget.h:12: 错误:forward de ...
- 使用MYCAT轻松实现MYSQL水平分片
完整文章下载地址:http://download.csdn.net/detail/dreamcode/9383516 简单来说,我们能够将数据的水平切分理解为是依照数据行的切分.就是将表中的某些行切分 ...
- poj3708(公式化简+大数进制装换+线性同余方程组)
刚看到这个题目,有点被吓到,毕竟自己这么弱. 分析了很久,然后发现m,k都可以唯一的用d进制表示.也就是用一个ai,和很多个bi唯一构成. 这点就是解题的关键了. 之后可以发现每次调用函数f(x),相 ...
- 九度OJ 1254:N皇后问题 (N皇后问题、递归、回溯)
时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:765 解决:218 题目描述: N皇后问题,即在N*N的方格棋盘内放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一 ...