【BZOJ2038】小Z的袜子【莫队】
题意
给出包含n个数字的序列,和m个查询。每次查询问区间[l,r]中挑选出两个数字,大小相同的概率为多少。
分析
莫队的入门题吧。代码是非常好写,关键是时间复杂度的证明。O(n*sqrt(n))。我还有点迷糊,等我再做几个题再说···
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cmath> 6 7 using namespace std; 8 typedef long long LL; 9 const int maxn=50000+100; 10 int val[maxn],belong[maxn],f[maxn]; 11 int n,m,cnt,block; 12 LL gcd(LL a,LL b){ 13 if(!b)return a; 14 return gcd(b,a%b); 15 } 16 17 struct Node{ 18 int L,R,id; 19 bool operator<(const Node& rhs)const{ 20 return belong[L]<belong[rhs.L]||(belong[L]==belong[rhs.L]&&R<rhs.R); 21 } 22 LL a,b; 23 void solve(){ 24 LL r=gcd(a,b); 25 a/=r,b/=r; 26 } 27 }ask[maxn]; 28 int cmp(Node a,Node b){ 29 return a.id<b.id; 30 } 31 LL ans; 32 void update(int p,int addv){ 33 ans=ans+2*addv*f[val[p]]+1; 34 f[val[p]]+=addv; 35 } 36 37 int main(){ 38 scanf("%d%d",&n,&m); 39 memset(f,0,sizeof(f)); 40 for(int i=1;i<=n;i++) 41 scanf("%d",&val[i]); 42 block=sqrt(n); 43 cnt=n/block; 44 if(n%block)cnt++; 45 for(int i=1;i<=n;i++){ 46 belong[i]=(i-1)/block+1; 47 } 48 for(int i=1;i<=m;i++){ 49 scanf("%d%d",&ask[i].L,&ask[i].R); 50 ask[i].id=i; 51 } 52 53 sort(ask+1,ask+1+m); 54 ans=0; 55 int l=1,r=0; 56 for(int i=1;i<=m;i++){ 57 if(r<ask[i].R){ 58 for(r=r+1;r<ask[i].R;r++){ 59 update(r,1); 60 } 61 update(r,1); 62 } 63 if(l>ask[i].L){ 64 for(l=l-1;l>ask[i].L;l--){ 65 update(l,1); 66 } 67 update(l,1); 68 } 69 if(r>ask[i].R){ 70 for(;r>ask[i].R;r--){ 71 update(r,-1); 72 } 73 } 74 if(l<ask[i].L){ 75 for(;l<ask[i].L;l++){ 76 update(l,-1); 77 } 78 } 79 if(ask[i].L==ask[i].R){ 80 ask[i].a=0,ask[i].b=1; 81 continue; 82 } 83 ask[i].a=ans-(ask[i].R-ask[i].L+1),ask[i].b=(LL)(ask[i].R-ask[i].L+1)*(ask[i].R-ask[i].L); 84 ask[i].solve(); 85 } 86 sort(ask+1,ask+1+m,cmp); 87 for(int i=1;i<=m;i++){ 88 printf("%lld/%lld\n",ask[i].a,ask[i].b); 89 } 90 return 0; 91 }