http://acm.hdu.edu.cn/showproblem.php?pid=4630
离散化+树状数组
将数组 *a 从后向前遍历 遍历到 a[x] 的时候 再枚举a[x]的约数 假如 约数 k
last[k] 对应到 上一个k出现的位置 那么可被公约数 k 更新的区间是 last[k] --- 最后
把所有a[x]的约数都处理完之后 从 x 到任意 y(y>=x)形成的段的 最优解都可求
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<cmath> #include<set> #include<vector> #include<list> using namespace std; typedef long long ll; typedef pair<double,double>ppd; const double PI = acos(-1.); const double eps = (1e-9); const int N=50001; struct node { int l,r; int index; }q[N]; int a[N],last[N],ans[N]; int c[N]; int lowbit(int x) { return x&(-x); } void update(int i,int k) { while(i<N) { c[i]=max(c[i],k); i+=lowbit(i); } } int getM(int i) { int tmp=0; while(i>=1) { tmp=max(tmp,c[i]); i-=lowbit(i); } return tmp; } bool cmp(const node &x,const node &y) { return x.l>y.l; } int main() { //freopen("data.in","r",stdin); int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); int Q; scanf("%d",&Q); for(int i=0;i<Q;++i) { scanf("%d %d",&q[i].l,&q[i].r); q[i].index=i; } sort(q,q+Q,cmp); memset(c,0,sizeof(c)); memset(last,-1,sizeof(last)); int ln=0; for(int i=n;i>=1;--i) { for(int x=1;x*x<=a[i];++x) if(a[i]%x==0) { if(last[x]!=-1) update(last[x],x); last[x]=i; int y=a[i]/x; if(x==y) continue; if(last[y]!=-1) update(last[y],y); last[y]=i; } while(ln<Q&&q[ln].l==i) { ans[q[ln].index]=getM(q[ln].r); ++ln; } } for(int i=0;i<Q;++i) printf("%d\n",ans[i]); } return 0; }