题目链接:https://www.luogu.com.cn/problem/P1494
一道很经典的莫队模板题,然而每道莫队题的大体轮廓都差不多。
首先莫队是一种基于分块的算法,它的显著特点就是:
能在$O(1)$的时间内从$(l,r)$转换到$(l,r-1),(l-1,r),(l+1,r),(l,r+1)$。
然后它的总复杂度在$O(n imes sqrt{n})$左右。
这道题中除了莫队的应用外,还需要处理一个组合数$(cul)$和一个$gcd$,然后跑莫队即可。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 6 using namespace std; 7 typedef long long ll; 8 const int N=1000000+10; 9 10 int a[N],vis[N]; 11 int ans1[N],ans2[N]; 12 ll ans; 13 int block; 14 15 struct node{ 16 int l,r; 17 int id; 18 }q[N]; 19 20 ll cul(ll x){ 21 return x*(x-1)/2; 22 } 23 24 bool cmp(node aa,node bb){ 25 if(aa.l/block==bb.l/block) return aa.r<bb.r; 26 return aa.l/block<bb.l/block; 27 } 28 29 void add(int pos){ 30 vis[a[pos]]++; 31 ll m=vis[a[pos]]; 32 ans=ans-cul(m-1)+cul(m); 33 } 34 35 void del(int pos){ 36 vis[a[pos]]--; 37 ll m=vis[a[pos]]; 38 ans=ans-cul(m+1)+cul(m); 39 } 40 41 int gcd(int n,int m){ 42 if(m==0) return n; 43 return gcd(m,n%m); 44 } 45 46 int main(){ 47 int n,m; 48 scanf("%d%d",&n,&m); 49 block=sqrt(n); 50 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 51 int L=1,R=0; 52 for(int i=1;i<=m;i++){ 53 scanf("%d%d",&q[i].l,&q[i].r); 54 q[i].id=i; 55 } 56 sort(q+1,q+m+1,cmp); 57 for(int i=1;i<=m;i++){ 58 while(L<q[i].l){ 59 del(L); 60 L++; 61 } 62 while(L>q[i].l){ 63 L--; 64 add(L); 65 } 66 while(R>q[i].r){ 67 del(R); 68 R--; 69 } 70 while(R<q[i].r){ 71 R++; 72 add(R); 73 } 74 ans1[q[i].id]=ans; 75 ans2[q[i].id]=cul(q[i].r-q[i].l+1); 76 } 77 for(int i=1;i<=m;i++){ 78 int g=gcd(ans1[i],ans2[i]); 79 if(ans1[i]==0){ 80 printf("0/1 "); 81 continue; 82 } 83 printf("%d/%d ",ans1[i]/g,ans2[i]/g); 84 } 85 return 0; 86 }