http://acm.hdu.edu.cn/showproblem.php?pid=4630
No Pain No Game
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 72 Accepted Submission(s): 21
Problem Description
Life is a game,and you lose it,so you suicide.
But you can not kill yourself before you solve this problem:
Given you a sequence of number a 1, a 2, ..., a n.They are also a permutation of 1...n.
You need to answer some queries,each with the following format:
If we chose two number a,b (shouldn't be the same) from interval [l, r],what is the maximum gcd(a, b)? If there's no way to choose two distinct number(l=r) then the answer is zero.
But you can not kill yourself before you solve this problem:
Given you a sequence of number a 1, a 2, ..., a n.They are also a permutation of 1...n.
You need to answer some queries,each with the following format:
If we chose two number a,b (shouldn't be the same) from interval [l, r],what is the maximum gcd(a, b)? If there's no way to choose two distinct number(l=r) then the answer is zero.
Input
First line contains a number T(T <= 5),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1 <= n <= 50000).
The second line contains n number a 1, a 2, ..., a n.
The third line contains a number Q(1 <= Q <= 50000) denoting the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n),denote a query.
Then follow T test cases.
For each test cases,the first line contains a number n(1 <= n <= 50000).
The second line contains n number a 1, a 2, ..., a n.
The third line contains a number Q(1 <= Q <= 50000) denoting the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n),denote a query.
Output
For each test cases,for each query print the answer in one line.
思路:设数列为a[1]~a[n] ,我们·‚从左往右扫描,依次加入a[i],我们设r为当前位置,po[x]为当前位置之前,有因数x的数所出现的位置中,最靠右的那个位置,设dp[i]为位置i到当前为位置r之间(也就是区间[i,r])GCD的最大值,则我们枚举a[i]的所有因数xi,则我们可以将区间[1,po[xi]]中所有小于xi的dp项赋值为xi,这可以用线段树来维护,更新后再将po[xi]=r,那么枚举玩a[i]的所有因数后,我们可以知道对于所有l(l<=r)区间[l,r]中GCD的最大值。所以我们需要一开始将1到50000的所有因数求出来,并且将询问按照R从小到大排序,离线处理即可。以下是代码。
线段树写的很挫,G++还TLE了,C++1700ms卡过。。。仅供参考。。。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <vector> #define maxn 50010 #define mid ((t[p].l+t[p].r)>>1) #define ls (p<<1) #define rs (ls|1) using namespace std; struct tree { int l,r; int lazy; }t[maxn<<2]; void pushdown(int p) { if(t[p].lazy) { t[ls].lazy=max(t[ls].lazy,t[p].lazy); t[rs].lazy=max(t[rs].lazy,t[p].lazy); t[p].lazy=0; } } void build(int p,int l,int r) { t[p].l=l,t[p].r=r,t[p].lazy=0; if(l==r) { return; } build(ls,l,mid); build(rs,mid+1,r); } void change(int p,int l,int r,int val) { if(t[p].l==l&&t[p].r==r) { t[p].lazy=max(t[p].lazy,val); return; } pushdown(p); if(l>mid) change(rs,l,r,val); else if(r<=mid) change(ls,l,r,val); else { change(ls,l,mid,val); change(rs,mid+1,r,val); } } int query(int p,int x) { if(t[p].l==t[p].r) return t[p].lazy; pushdown(p); if(x>mid) return query(rs,x); else return query(ls,x); } vector<int> vec[maxn]; void init() { int i; for(i=1;i<=50000;i++) { for(int j=i;j<=50000;j+=i) { vec[j].push_back(i); } } } int po[maxn],a[maxn],ans[maxn]; struct ask { int num; int l,r; }as[maxn]; bool cmp(ask a,ask b) { return a.r<b.r; } int main() { // freopen("dd.txt","r",stdin); init(); int ncase; scanf("%d",&ncase); while(ncase--) { int n,i,q; scanf("%d",&n); build(1,1,n); for(i=1;i<=n;i++) { scanf("%d",&a[i]); po[i]=0; } scanf("%d",&q); for(i=1;i<=q;i++) { scanf("%d%d",&as[i].l,&as[i].r); as[i].num=i; } sort(as+1,as+q+1,cmp); int qnum=1; as[q+1].r=maxn; for(i=1;i<=n;i++) { for(int j=0;j<vec[a[i]].size();j++) { int tmp=vec[a[i]][j]; if(po[tmp]) { change(1,1,po[tmp],tmp); } po[tmp]=i; } while(as[qnum].r<=i) { ans[as[qnum].num]=query(1,as[qnum].l); qnum++; } if(qnum>q) break; } for(i=1;i<=q;i++) { printf("%d\n",ans[i]); } } return 0; }