hdu 5726 GCD (区间RMQ )
2017-10-25 14:41
183 查看
题意: 给你n个数和m个查询,输出区间的gcd的值,和问你还有几个区间的gcd值等于你查询的gcd的值。
思路:和上体一样,首先区间GCD是一个单调递减的区间,我们就可以直接 维护一个区间GCD的值,之后枚举左端点二分去找我们与区间GCD值相同的区间,就好了看代码吧
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <iostream>
const int maxn = 110000;
using namespace std;
long long a[maxn],dp[maxn][20];
int n;
map<int,long long>Map;
long long gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void init()
{
for(int i = 1 ;i <= n ;i++)
{
dp[i][0] = a[i];
}
for(int j = 1 ; (1<<j)<=n ;j++)
{
for(int i = 1 ; i+(1<<j)-1<=n ;i++)
{
dp[i][j] = gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l,int r)
{
int k = 0 ;
while(1<<(k+1)<=(r-l+1)) k++;
return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lower_b(int l,int r,int p)
{
int s = r+1;
while(l<r)
{
int mid = (l+r+1)>>1;
// cout<<l<<" "<<r<<endl;
if(RMQ(l,mid)==p)
{
l = mid;
}
else
{
r = mid-1;
}
}
return l;
}
int main()
{
int t;
scanf("%d",&t);
int cnt = 1 ;
while(t--)
{
Map.clear();
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&a[i]);
}
init();
int m,l,r,mid;
int p;
for(int i = 1 ; i <= n ; i++)
{
p = dp[i][0]; //枚举左端点
int j = i;
while(j<=n)
{
l = j ,r = n;
l = lower_b(l,r,p); //二分去找和当前gcd值相同的区间的位置,
Map[p]+=l-j+1; //j为区间左端点,l为gcd相同的区间的位置
j = l+1; //开始找到下一个
p = RMQ(i,j);
}
}
scanf("%d",&m);
printf("Case #%d:\n",cnt++);
while(m--)
{
scanf("%d%d",&l,&r);
int ans = RMQ(l,r);
printf("%d %lld\n",ans,Map[ans]);
}
}
}
思路:和上体一样,首先区间GCD是一个单调递减的区间,我们就可以直接 维护一个区间GCD的值,之后枚举左端点二分去找我们与区间GCD值相同的区间,就好了看代码吧
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <iostream>
const int maxn = 110000;
using namespace std;
long long a[maxn],dp[maxn][20];
int n;
map<int,long long>Map;
long long gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void init()
{
for(int i = 1 ;i <= n ;i++)
{
dp[i][0] = a[i];
}
for(int j = 1 ; (1<<j)<=n ;j++)
{
for(int i = 1 ; i+(1<<j)-1<=n ;i++)
{
dp[i][j] = gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l,int r)
{
int k = 0 ;
while(1<<(k+1)<=(r-l+1)) k++;
return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lower_b(int l,int r,int p)
{
int s = r+1;
while(l<r)
{
int mid = (l+r+1)>>1;
// cout<<l<<" "<<r<<endl;
if(RMQ(l,mid)==p)
{
l = mid;
}
else
{
r = mid-1;
}
}
return l;
}
int main()
{
int t;
scanf("%d",&t);
int cnt = 1 ;
while(t--)
{
Map.clear();
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&a[i]);
}
init();
int m,l,r,mid;
int p;
for(int i = 1 ; i <= n ; i++)
{
p = dp[i][0]; //枚举左端点
int j = i;
while(j<=n)
{
l = j ,r = n;
l = lower_b(l,r,p); //二分去找和当前gcd值相同的区间的位置,
Map[p]+=l-j+1; //j为区间左端点,l为gcd相同的区间的位置
j = l+1; //开始找到下一个
p = RMQ(i,j);
}
}
scanf("%d",&m);
printf("Case #%d:\n",cnt++);
while(m--)
{
scanf("%d%d",&l,&r);
int ans = RMQ(l,r);
printf("%d %lld\n",ans,Map[ans]);
}
}
}
相关文章推荐
- HDU 5726 GCD (rmq+二分 or 线段树 维护区间gcd)
- hdu 5726 区间gcd RMQ+二分 || 暴力枚举
- HDU 5726 求gcd=k的区间的个数 (二分+RMQ)
- hdu 5726 GCD (区间gcd-RMQ)
- HDU 5726 GCD(RMQ+二分)
- hdu 5726 (线段树 GCD RMQ)多校第一场1004
- HDU 5726 GCD 区间gcd查询 MAP RMQ 优化
- HDU 5726 GCD(RMQ 查询 + 二分)
- HDU 5726 区间GCD=k的个数
- HDU 5726 GCD(RMQ+二分,详解,ST算法)
- hdu 5726(区间gcd)
- HDU 5726 GCD(rmq+二分)
- Hdu 5726 GCD【思维+二分+区间Gcd】好题!
- HDU 5726 GCD 【区间GCD + 暴力预处理】
- hdu 5726 GCD RMQ+二分枚举
- hdu 5726 GCD (线段树 + 区间预处理)
- hdu 5726 GCD 暴力倍增rmq
- HDU 5726-D-GCD- RMQ+二分
- HDU 5726 GCD(RMQ+二分)
- hdu 5726 GCD rmq 二分