HDU 5381(The sum of gcd-莫队算法解决区间段gcd的和)

来源:互联网 发布:网络咨询话术 编辑:程序博客网 时间:2024/05/20 19:45

The sum of gcd

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 784    Accepted Submission(s): 335


Problem Description
You have an array A,the length of A is n
Let f(l,r)=ri=lrj=igcd(ai,ai+1....aj)
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integers n
Second line has n integers Ai
Third line has one integers Q,the number of questions
Next there are Q lines,each line has two integers l,r
1T3
1n,Q104
1ai109
1l<rn
 

Output
For each question,you need to print f(l,r)
 

Sample Input
251 2 3 4 531 32 31 444 2 6 931 32 42 3
 

Sample Output
9616182310
 

Author
SXYZ
 

Source
2015 Multi-University Training Contest 8
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:  5421 5420 5419 5418 5417 
 

预处理一段的gcd

我们发现一段的gcd是一样的

1 2 3 6 6 6 12

1 1 3 6 6 6 12 //从12开始向左的gcd

显然最多有logN段,接下来用莫队算法+杨氏转移 

O(nlogn+nsqrt(n)logn)=O(n^1.5*logn)



#include<bits/stdc++.h> using namespace std;#define For(i,n) for(int i=1;i<=n;i++)#define Fork(i,k,n) for(int i=k;i<=n;i++)#define Rep(i,n) for(int i=0;i<n;i++)#define ForD(i,n) for(int i=n;i;i--)#define ForkD(i,k,n) for(int i=n;i>=k;i--)#define RepD(i,n) for(int i=n;i>=0;i--)#define Forp(x) for(int p=pre[x];p;p=next[p])#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  #define Lson (x<<1)#define Rson ((x<<1)+1)#define MEM(a) memset(a,0,sizeof(a));#define MEMI(a) memset(a,127,sizeof(a));#define MEMi(a) memset(a,128,sizeof(a));#define INF (2139062143)#define F (100000007)#define MAXN (10000+10)typedef long long ll;ll mul(ll a,ll b){return (a*b)%F;}ll add(ll a,ll b){return (a+b)%F;}ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}void upd(ll &a,ll b){a=(a%F+b%F)%F;}int n,a[MAXN],Q;struct seg {int l,r,i;friend bool operator<(seg a,seg b){ return (int)((a.l)/sqrt(n))^(int)((b.l)/sqrt(n))?(int)((a.l)/sqrt(n))<(int)((b.l)/sqrt(n)):a.r<b.r;}}comm[MAXN];ll ans[MAXN];ll gcd(ll a,ll b){if (b==0) return a; return gcd(b,a%b);}int h[MAXN][100]={0};ll val[MAXN][100]={0};void init(int h[][100],ll  val[][100]){MEM(val) MEM(h)For(i,n) h[i][0]=0;h[1][0]=1; h[1][1]=1; val[1][1]=a[1];Fork(i,2,n) {int &k=h[i][0];val[i][++k]=a[i];h[i][k]=i;For(j,h[i-1][0]) {ll p=gcd(val[i][k],val[i-1][j]);if (p!=val[i][k]) val[i][++k]=p;h[i][k]=h[i-1][j];}}}int h2[MAXN][100]={0};ll val2[MAXN][100]={0};void init2(int h[][100],ll  val[][100]){MEM(val) MEM(h)For(i,n) h[i][0]=0;h[n][0]=1; h[n][1]=n; val[n][1]=a[n];ForD(i,n-1) {int &k=h[i][0];val[i][++k]=a[i];h[i][k]=i;For(j,h[i+1][0]) {ll p=gcd(val[i][k],val[i+1][j]);if (p!=val[i][k]) val[i][++k]=p;h[i][k]=h[i+1][j];}}}ll modify(){return 0;}ll modify(int l,int r,int f){ll ret=0;if (f==0) {  //left int fro=l;For(j,h2[l][0]) {int last=min(h2[l][j],r);if (fro<=last) ret+=val2[l][j]*(last-fro+1);fro=last+1;if (fro>r) break;}} else {int last=r;For(j,h[r][0]) {int fro=max(h[r][j],l);if (fro<=last) ret+=val[r][j]*(last-fro+1);last=fro-1;if (fro<l) break;}}return ret;}int main(){//freopen("B.in","r",stdin);int T; cin>>T;while(T--) {cin>>n;For(i,n) scanf("%d",&a[i]);init(h,val);init2(h2,val2);cin>>Q;MEM(ans) For(i,Q){ scanf("%d%d",&comm[i].l,&comm[i].r),comm[i].i=i;}sort(comm+1,comm+1+Q);int nowl=1,nowr=1;ll nowans=a[1];For(i,Q){while (nowl<comm[i].l) nowans-=modify(nowl,nowr,0),nowl++;while (nowl>comm[i].l) nowans+=modify(nowl-1,nowr,0),nowl--;while (comm[i].r<nowr) nowans-=modify(nowl,nowr,1),nowr--;while (comm[i].r>nowr) nowans+=modify(nowl,nowr+1,1),nowr++;ans[comm[i].i]=nowans; }For(i,Q) printf("%I64d\n",ans[i]);} return 0;}






0 0
原创粉丝点击