Rabbit Kingdom(hdu 4777 求區間內與所有數都互質的數的個數 樹狀陣列)
阿新 • • 發佈:2018-12-10
題目連結:
hdu英文題面,牛客中文題面,一個意思。
題意:
有一個長度為 n 的序列,m 個詢問。每個詢問求區間內與所有數都互質的數的個數。
思路:
對於序列中每一個位置,用 l[i] 儲存位置 i 左側第一個與其不互質的數,用 r[i] 儲存位置 i 右側第一個與其不互質的數。
離線處理詢問,把詢問按右端點從小到大排序。使用樹狀陣列維護不互質的數的個數,那麼互質的數的個數等於區間長度減去不互質的數的個數。
樹狀陣列的維護:遍歷一遍序列,對於每個位置,用樹狀陣列使其 l[i] 的位置上 +1 ,若這個點是位置 j 的右端點,那麼使 j 的位置上 +1,在 l[j] 的位置上 -1 。若該位置為一個查詢的右端點,計算答案。(樹狀陣列更新的原理自己手算一遍能更好地理解,如算一下3 6 3 5 10 12這個樣例)
對於每個查詢用區間長度 - 樹狀陣列求和即可得到答案。
Code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAX = 2e5+10; const ll mod = 1000000007; typedef struct{ int l,r,id; }Point; int n,m; int a[MAX+10]; Point op[MAX+10]; int c[MAX+10]; int l[MAX+10],r[MAX+10]; int tmp[MAX+10]; bool vis[MAX+10]; int prime[MAX+10]; vector<int>mp[MAX+10]; vector<int>vec[MAX+10]; int ans[MAX+10]; void init() { for(int i=0;i<=n;i++){ l[i]=0; r[i]=n+1; vec[i].clear(); } vec[n+1].clear(); memset(c,0,sizeof(c)); } bool cmp(Point x,Point y) { return x.r<y.r; } void getprime() { memset(vis,0,sizeof(vis)); int num=0; for(int i=2;i<=MAX;i++){ if(!vis[i]){ prime[++num]=i; } for(int j=1;j<=num&&i*prime[j]<=MAX;j++){ vis[i*prime[j]]=true; if(i%prime[j]==0) break; } } for(int i=1;i<=num;i++){ for(int j=1;j*prime[i]<=MAX;j++){ mp[j*prime[i]].push_back(prime[i]); } } } int lowbit(int x) { return x&(-x); } void add(int k, int x) { if(k==0){ return; } while (k <= n) { c[k] += x; k += lowbit(k); } } int sum(int x) { int val = 0; while (x) { val += c[x]; x -= lowbit(x); } return val; } int main() { getprime(); while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=m;i++){ scanf("%d%d",&op[i].l,&op[i].r); op[i].id=i; } init(); //注意tmp[ ]陣列置0的範圍為 0 - MAX //因為a[i]質因數的範圍在 0 - MAX for(int i=0;i<=MAX;i++) tmp[i]=0; for(int i=1;i<=n;i++){ for(int j=0;j<mp[a[i]].size();j++){ l[i]=max(l[i],tmp[mp[a[i]][j]]); tmp[mp[a[i]][j]]=i; } } for(int i=0;i<=MAX;i++) tmp[i]=n+1; for(int i=n;i>=1;i--){ for(int j=0;j<mp[a[i]].size();j++){ r[i]=min(r[i],tmp[mp[a[i]][j]]); tmp[mp[a[i]][j]]=i; } } for(int i=1;i<=n;i++){ vec[r[i]].push_back(i); } sort(op+1,op+m+1,cmp); int pos=1; for(int i=1;i<=m;i++){ while(pos<=n&&pos<=op[i].r){ add(l[pos],1); for(int j=0;j<vec[pos].size();j++){ add(vec[pos][j],1); add(l[vec[pos][j]],-1); } pos++; } ans[op[i].id]=op[i].r-op[i].l+1-(sum(op[i].r)-sum(op[i].l-1)); } for(int i=1;i<=m;i++){ printf("%d\n",ans[i]); } } return 0; }