【序列莫队】BZOJ2038- [2009国家集训队]小Z的袜子(hose)
【题目大意】
给出1-N只袜子的颜色,多次询问L-R中选出一双同色袜子的概率。
【思路】
裸莫队。基本的莫队步骤:
①分组(每组大小为根号sqrt(n),共sqrt(n)组)
②排序(左边界分组,右边界在组内按大小排序)
③暴力转移
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int MAXN=50000+50; 8 typedef long long ll; 9 struct node 10 { 11 int l,r,id,pos; 12 ll ansa,ansb; 13 }; 14 int n,m,c[MAXN]; 15 ll ans=0,s[MAXN]; 16 ll sqr(ll x){return x*x;} 17 node q[MAXN]; 18 19 ll gcd(ll a,ll b) 20 { 21 if (b==0) return a; 22 else return gcd(b,a%b); 23 } 24 25 bool cmp(node a,node b) 26 { 27 if (a.pos==b.pos) return (a.r<b.r); 28 else return (a.pos<b.pos); 29 } 30 31 bool cmp_id(node a,node b) 32 { 33 return (a.id<b.id); 34 } 35 36 void update(int x,int delta) 37 { 38 ans-=sqr(s[c[x]]); 39 s[c[x]]+=delta; 40 ans+=sqr(s[c[x]]); 41 } 42 43 void init() 44 { 45 memset(s,0,sizeof(s)); 46 memset(c,0,sizeof(c)); 47 scanf("%d%d",&n,&m); 48 for (int i=1;i<=n;i++) scanf("%d",&c[i]); 49 int block=int(sqrt(n)); 50 for (int i=0;i<m;i++) 51 { 52 scanf("%d%d",&q[i].l,&q[i].r); 53 q[i].id=i; 54 q[i].pos=(q[i].l-1)/block+1; 55 } 56 sort(q,q+m,cmp); 57 } 58 59 void solve() 60 { 61 int l=1,r=1; 62 s[c[1]]=1,ans=sqr(s[c[1]]); 63 for (int t=0;t<m;t++) 64 { 65 for (;r<q[t].r;r++) update(r+1,1); 66 for (;r>q[t].r;r--) update(r,-1); 67 for (;l<q[t].l;l++) update(l,-1); 68 for (;l>q[t].l;l--) update(l-1,1); 69 if (l==r) 70 { 71 q[t].l=0;q[t].r=1; 72 continue; 73 } 74 q[t].ansa=ans-(r-l+1); 75 q[t].ansb=(ll)(r-l+1)*(r-l); 76 ll minx=min(q[t].ansa,q[t].ansb),maxx=max(q[t].ansa,q[t].ansb); 77 ll k=gcd(maxx,minx); 78 q[t].ansa/=k,q[t].ansb/=k; 79 } 80 } 81 82 void print() 83 { 84 sort(q,q+m,cmp_id); 85 for (int i=0;i<m;i++) printf("%lld/%lld\n",q[i].ansa,q[i].ansb); 86 } 87 88 int main() 89 { 90 init(); 91 solve(); 92 print(); 93 return 0; 94 }