#6164. 「美團 CodeM 初賽 Round A」數列互質-莫隊
阿新 • • 發佈:2019-01-08
#6164. 「美團 CodeM 初賽 Round A」數列互質
思路 : 對這個題來言,莫隊可以 n*根號n 離線處理出各個數出現個的次數 ,同時可以得到每個次數出現的次數 ,
但是還要處理有多少 次數 與ki互質 。根據數列的性質,無論這個區間多長,最長也就是 1 - n這個區間 ,所能產生的
不同的次數 也就是 根號 n 種 例如 長度為28的 數列 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 不同的次數 只有 7種
數列越長了 這個性質體現的越明顯, 原因就是 根據他們的出現的次數求個和 就算他們都按 最小的次數出現的話 1 2 3 4...s 求和為 (1+s)*s/2
而這個數又不能超過 區間長度 ,所以 這個 s也就在 根號 長度左右。 所以可以放心的進行暴力求解,有插入刪除操作,可以陣列模擬連結串列實現。
#include<bits/stdc++.h> using namespace std; #define maxn 55555 int n,m,cnt[maxn*2],tong[maxn*2],block,ans[maxn],data[maxn]; int nxt[maxn*2],lst[maxn*2],head=0,tail=maxn-1,l,r; struct node { int l,r,k,id; bool operator <(const node &b)const { return l/block==b.l/block?r<b.r:l<b.l; } } a[maxn]; void upda(int rd) { if(rd<=head)return; nxt[rd]=nxt[head]; nxt[head]=rd; lst[rd]=head; lst[nxt[rd]]=rd; } void rmove(int rd) { if(rd<=head)return; nxt[lst[rd]]=nxt[rd]; lst[nxt[rd]]=lst[rd]; } void ins(int x) { if(--tong[cnt[x]]==0)rmove(cnt[x]); if(++tong[++cnt[x]]==1)upda(cnt[x]); } void del(int x) { if(--tong[cnt[x]]==0)rmove(cnt[x]); if(++tong[--cnt[x]]==1)upda(cnt[x]); } int main() { scanf("%d%d",&n,&m); block=sqrt(n); nxt[0]=tail; lst[tail]=0; for(int i=1; i<=n; i++) scanf("%d",&data[i]); for(int i=0; i<m; i++) { a[i].id=i; scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].k); } sort(a,a+m); l=a[0].l; r=a[0].l-1; for(int i=0; i<m; i++) { while(l>a[i].l) ins(data[--l]); while(l<a[i].l) del(data[l++]); while(r>a[i].r) del(data[r--]); while(r<a[i].r) ins(data[++r]); int cp=0; for(int j=nxt[head]; j!=tail; j=nxt[j]) if(__gcd(a[i].k,j)==1) cp+=tong[j]; ans[a[i].id]=cp; } for(int i=0; i<m; i++)printf("%d\n",ans[i]); return 0; }