NOIP2018模擬賽 HDU 4630 No Pain No Game 2018 10 9 T1
阿新 • • 發佈:2018-11-09
難度:NOIP+
演算法:離線+樹狀陣列
簡述題意:
1.1 題目描述 給定一個長度為n 的排列a1; a2; a3; :::; an, 現在有Q 個詢問,每次詢 問區間[l,r] 內任意選取兩個不同的數字能夠得到的gcd 的最大值。 1.2 輸入 一行兩個整數n;Q 接下來一行是一個長度為n 的排列。 1.3 輸出 如題目描述所述 1.4 樣例輸入1 10 5 8 2 4 9 5 7 10 6 1 3 2 10 2 4 6 9 1 4 7 10 1.5 樣例輸出1 5 2 2 4 3 1.6 資料規模與約定 本題共十個測試點 對於1,2,3 三個測試點總有n;Q 1000. 對於全部測試點有n;Q 105
題解:
首先,它是一道套路題(我們教練說的,哈哈哈)
離線儲存,排序,加上樹狀陣列。
易證,每回都要記錄他的因數上一次出現的位置,當然每回更新最大值的時候也是取最大值,
好吧,,,你們聽不明白我在說什麼,但是我還是要接著說。
然後呢,你需要逆序處理,每次跑樹狀陣列求區間最大值,就好了!
PS;[l, r] 這個數學公式,彷彿l和r可以取到等號!
#include <cstdio> #include <iostream> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #define ll long long #define N 500005 using namespace std; int a[N],c[N],n; int lowbit(int x) { return x & -x; } void add(int x,int val) { while(x) { c[x]=max(val,c[x]); x-=lowbit(x); } } int getmax(int x) { int ret=0; while(x<=n) { ret=max(ret,c[x]); x+=lowbit(x); } return ret; } struct node { int l,r,idd; }S[N]; int cmp(node a,node b) { return a.r<b.r; } int cmp1(node a,node b) { return a.idd<b.idd; } int pre[N],ans[N]; int main() { freopen("A.in","r",stdin); freopen("A.out","w",stdout); scanf("%d",&n); int q; scanf("%d",&q); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } for(int i = 1;i <= q;i++) { scanf("%d%d",&S[i].l,&S[i].r); S[i].idd=i; } sort(S+1,S+1+q,cmp); int tnum = 1; for(int i = 1;i<=n;i++) { if(tnum == q) break; for(int j = 1;j*j<=a[i];j++) { if(a[i]%j==0) { if(pre[j]!=0) add(pre[j],j); pre[j]=i; if (j*j==a[i]) continue ; if(pre[a[i]/j]!=0) add(pre[a[i]/j],a[i]/j); pre[a[i]/j]=i; } } while(tnum<=q&&S[tnum].r==i) { ans[S[tnum].idd]=getmax(S[tnum].l); tnum++; } } sort(S+1,S+1+q,cmp1); for(int i = 1;i <= q;i++) { /*if(S[i].l==S[i].r) printf("0\n"); else*/ printf("%d\n",ans[i]); } return 0 ; }
如果你們實在是看不懂我的題解,也看不懂我的標程的話,請見大佬部落格: