2016 Multi-University Training Contest 1 1004 GCD HDU 5726 (RMQ)
2016-07-22 12:12
549 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5726
题目大意:
给你一串数,然后在给你多个区间让你求这个区间内的数的gcd
以及这整串数和这个区间gcd相等的子序列有多少个。
第一个问题求gcd很容易的吶
第二个问题需要求区间可以选择线段树。
这里安利一个求区间的算法RMQ算法
因为gcd是不增数列所以可以用到这个方法
先设A[]为题目给出的数串用样例1为代表
A[]={1,2,4,6,7};
然后我们设 a[i][j]数组为区间i到2^j之间的数的gcd值
所以
a[1][0]=1;a[1][1]=gcd(1,2);a[1][2]=gcd(1,2,4,6);
a[2][0]=2;a[2][1]=gcd(2,4);a[3][1]=gcd(4,6)
可以看出
a[2][1]=gcd(a[2][0],a[3][0]);
a[1][2]=gcd(a[1][1],a[3][1]);
从上可以推出状态转移方程
最后结果进行二分就可以了
题目大意:
给你一串数,然后在给你多个区间让你求这个区间内的数的gcd
以及这整串数和这个区间gcd相等的子序列有多少个。
第一个问题求gcd很容易的吶
long long gcd(long long a,long long b) { return a%b?gcd(b,a%b):b; }
第二个问题需要求区间可以选择线段树。
这里安利一个求区间的算法RMQ算法
因为gcd是不增数列所以可以用到这个方法
先设A[]为题目给出的数串用样例1为代表
A[]={1,2,4,6,7};
然后我们设 a[i][j]数组为区间i到2^j之间的数的gcd值
所以
a[1][0]=1;a[1][1]=gcd(1,2);a[1][2]=gcd(1,2,4,6);
a[2][0]=2;a[2][1]=gcd(2,4);a[3][1]=gcd(4,6)
可以看出
a[2][1]=gcd(a[2][0],a[3][0]);
a[1][2]=gcd(a[1][1],a[3][1]);
从上可以推出状态转移方程
void rmq(long long num) { for(int j=0;j<30;j++) for(int i=1;i<=num&&i+(1<<j)-1<=num;i++) { if(j==0) ans[i][j]=a[i]; else ans[i][j]=gcd(ans[i][j-1],ans[i+(1<<j-1)][j-1]);//状态转移方程 } }
最后结果进行二分就可以了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<map>
#include<math.h>
#define M 100006
using namespace std;
long long ans[M][40];
long long a[M];
map<int,long long>q;
long long gcd(long long a,long long b) { return a%b?gcd(b,a%b):b; }
void rmq(long long num) { for(int j=0;j<30;j++) for(int i=1;i<=num&&i+(1<<j)-1<=num;i++) { if(j==0) ans[i][j]=a[i]; else ans[i][j]=gcd(ans[i][j-1],ans[i+(1<<j-1)][j-1]);//状态转移方程 } }
int find(int L,int R) //查找区间 区间长度为R-L+1
{
int k=log2(R-L+1);
return gcd(ans[L][k],ans[R-(1<<k)+1][k]);
}
int main()
{
int T;
int cas=0;
scanf("%d",&T);
while(T--)
{
printf("Case #%d:\n",++cas);
memset(ans,0,sizeof(ans));
long long g[M];
long long n;
scanf("%lld",&n);
int i,j,k;
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
rmq(n);
int m;
scanf("%d",&m);
for(i=1;i<=n;i++) //固定初始点
{
int st=i;
while(st<=n)
{
int t=0;
int head=st;
int ed=n;
int v=find(i,st);
while(head<=ed) //二分结果
{
int mid=(head+ed)/2;
int now=find(i,mid);
if(now==v)
{
t=mid;
head=mid+1;
}
else if(now<v)
{
ed=mid-1;
}
else
{
head=mid+1;
}
}
q[v]+=t-st+1;
st=ed+1;
}
}
while(m--)
{
int aa,b;
scanf("%d%d",&aa,&b);
int k=find(aa,b);
printf("%d %lld\n",k,q[k]);
}
q.clear();
}
}
相关文章推荐
- 数学——Acperience ( HDU 5734) ( 2016 Multi-University Training Contest 2 1001 )
- AIO、NIO、BIO
- hdu 5745(2016 Multi-University Training Contest 2)
- 2016 Multi-University Training Contest 2 Acperience
- hdu 5744(2016 Multi-University Training Contest 2)
- 对于android.intent.action.MAIN和android.intent.category.LAUNCHER的理解
- hdu 5742 (2016 Multi-University Training Contest 2)
- 2016 Multi-University Training Contest 2-1005---HDU 5738 Eureka
- hdu 5734 (2016 Multi-University Training Contest 2)
- 11. Container With Most Water
- HDU 5475 La Vie en rose(暴力 2016 Multi-University Training Contest 2 )
- 2016 Multi-University Training Contest 2 Keep On Movin
- HDU 1789 Doing Homework again
- [172] Factorial Trailing Zeroes
- http://blog.csdn.net/qinjuning/article/details/7607214
- 报错: Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Lcom/baidu/
- 2016 Multi-University Training Contest 2 Acperience
- 2016 Multi-University Training Contest 2 1011 Keep On Movin
- http://blog.csdn.net/jijiji000111/article/details/47971879
- 【HDU】5734 Acperience(2016 Multi-University Training Contest 2)