题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5726
第一次打多校,没有什么经验,果断被虐,学长说多校切4题区域赛一般拿牌,比赛前感觉出题应该没什么问题,然而……一上午都在和老师讨论项目的事,等结束没有休息就切题,感觉好累
A题扔给队友,榜单07题5发5A,看了一下没什么思路,看题目有GCD,前几天刚训练数论专题,果断看了GCD,坑呀……简介一下吧
题意大概就是给你n个数(n<100000)q次查询(q<100000)首先问gcd(a[i…….j]),然后有多少对gcd(a[in……jn])与gcd(a[i…….j])相等.
前几天刚写过相似的题目,利用dp[i][j]去写,dp前i个数的gcd为j,如果此题ai较小的话可以去写,但是……那么就换方法,比赛时也没想到什么,比赛结束看标称才有点感悟(毕竟太菜)
第一问较简单,利用线段树求gcd较为简单(学了好久也忘了刚好熟悉一下)第二问就是先预处理出以i为开头的区间的各自的gcd值,用线段树维护区间gcd和查询,然后询问的时候直接输出即可。
/********************
Acm ID: OffensiveChild
Author: wzh
proverbs:yiroad keep straight on
Tittle:线段树求解区间GCD
Time:2016.07.20
*********************/
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
using namespace std;
const int maxm=1000+5;
const int maxn=100000+5;
const int INF=0x3f3f3f3f;
typedef long long ll;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch =='-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
int n;
int num[maxn];
int gcd(int a, int b) {
while(b) {
int r = a % b;
a = b;
b = r;
}
return a;
}
struct segtree
{
int g[4*maxn];
void build(int i,int l,int r)
{
if(l==r)
{
g[i]=num[l];
return;
}
int mid=(l+r)>>1;
build(2*i,l,mid);
build(2*i+1,mid+1,r);
g[i]=gcd(g[2*i],g[2*i+1]);
}
int query(int i,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return g[i];
int mid=(l+r)>>1;
int ls=0,rs=0;
if(L<=mid)ls=query(2*i,l,mid, L,R);
if(R>mid)rs=query(2*i+1,mid+1,r,L,R);
if(!ls)swap(ls,rs);
return gcd(ls,rs);
}
int search(int i,int l,int r,int L,int R,int cur,int &GCD)
{
if(L<=l&&r<=R)
{
if(gcd(g[i],GCD)<cur)
{
if(l==r)return l;
else
{
int mid=(l+r)>>1,ls=0,rs=0;
ls=search(2*i,l,mid,L,R,cur,GCD);
if(ls)return ls;
rs=search(2*i+1,mid+1,r,L,R,cur,GCD);
return rs;
}
}
else
{
GCD=gcd(g[i],GCD);
return 0;
}
}
int mid=(l+r)>>1,ls=0 ,rs=0;
if(L<=mid)ls=search(2*i,l,mid,L,R,cur,GCD);
if(ls)return ls;
if(R>mid)rs=search(2*i+1,mid+1,r,L,R,cur,GCD);
return rs;
}
}seg;
map<int ,ll>M;
int main()
{
int k=1;
int T;
T=read();
while(T--)
{
M.clear();
n=read();
for(int i=1; i<=n; i++)
{
num[i]=read();
}
seg.build(1,1,n);
int GCD,nex;
for(int i=1;i<=n;i++)
{
int g=seg.query(1,1,n,i,n);
for(int now=i,cur=num[i];now<=n;)
{
if(g==cur){M[g]+=n-now+1;break;}
GCD=num[i];
nex=seg.search(1,1,n,i,n,cur,GCD);
M[cur]+=nex-now;
now=nex;
cur=gcd(num[now],cur);
}
}
int q;
q=read();
printf("Case #%d:\n",k++);
int a,b,ans;
for(int i=1;i<=q;i++)
{
a=read();
b=read();
ans=seg.query(1,1,n,a,b);
printf("%d %I64d\n",ans,M[ans]);
}
}
return 0;
}