[题解] 2038: [2009国家集训队]小Z的袜子(hose)
莫队,卡常数
-
思路
-
设\(\text{Vis[i]}\)为元素\(\text{i}\)在区间\(\text{[L,R]}\)的出现次数
-
考虑区间\(\text{[L,R]}\)和元素\(\text{i}\),首次取出的概率为\(\frac{Vis[i]}{R-L+1}\),再次取出的概率是\(\frac{Vis[i]-1}{R-L}\)
-
对于区间\(\text{[L,R]}\),答案为\(\sum_{i=1}^{N}{\frac{Vis[i](Vis[i]-1)}{(R-L)*(R-L+1)}}\)。
-
这样,每次给变\(\text{[L,R]}\),分子的变化可以通过对前、后两项的值做差得到:
- 设X=Vis[i],有:
\[(X+1)X-(X)(X-1)=2X \] -
莫队这样修改即可。
-
-
Code
-
/************************************************************** Problem: 2038 User: Bj2002 Language: C++ Result: Accepted Time:11036 ms Memory:2584 kb ****************************************************************/ #include <stdio.h> #include <string.h> #include <algorithm> #define GC getchar() #define Clean(X,K) memset(X,K,sizeof(X)) using namespace std ; int Qread () { int X = 0 ; char C = GC ; while (C > '9' || C < '0') C = GC ; while (C >='0' && C <='9') { X = X * 10 + C - '0' ; C = GC ; } return X ; } long long GCD(long long M, long long N) { while (N != 0) { long long T = M % N; M = N; N = T; } return M; } const int Maxn = 50005 ; int N , M , A[Maxn] , Vis[Maxn] ; long long Ans[Maxn] , Sum[Maxn]; struct Node { int Left , Right , Place; }; Node Q[Maxn] ; bool Cmp (const Node &X , const Node &Y) { if (X.Left != Y.Left ) return X.Left < Y.Left ; if (X.Left & 1) return X.Right < Y.Right ; else return X.Right > Y.Right ; } bool Cmp2 (const Node &X , const Node &Y) { return X.Place < Y.Place ; } void Qwrite(int X) { if(X > 9) Qwrite(X / 10); putchar(X % 10 + '0'); } int main () { // freopen ("P1494.in" , "r" , stdin) ; // freopen ("P1494.out", "w" , stdout) ; N = Qread () , M = Qread (); for (int i = 1 ; i <= N; ++ i) A[i] = Qread () ; for (int i = 1 ; i <= M; ++ i) Q[i].Left = Qread () , Q[i].Right = Qread () , Q[i].Place = i ;; sort (Q + 1 , Q + 1 + M , Cmp) ; Clean (Vis , 0) ; int L , R ; long long Now = 0 ; L = R = Q[1].Left ; Vis[A[L]] = 1 ; for (int i = 1 ; i <= M; ++ i) { while (L < Q[i].Left ) { -- Vis[A[L]] ; Now -= (Vis[A[L]] << 1) ; ++ L ; } // cout << L <<' '<<R <<' '<<Now<<endl; while (R < Q[i].Right ) { ++ R ; Now += (Vis[A[R]] << 1) ; ++ Vis[A[R]] ; } // cout << L <<' '<<R <<' '<<Now<<endl; while (R > Q[i].Right ) { -- Vis[A[R]] ; Now -= (Vis[A[R]] << 1) ; -- R ; } // cout << L <<' '<<R <<' '<<Now<<endl; Ans[Q[i].Place] = Now , Sum[Q[i].Place ] = ((long long)Q[i].Right - Q[i].Left ) * (Q[i].Right - Q[i].Left + 1) ; } std :: sort (Q + 1 , Q + 1 + M , Cmp2) ; for (int i = 1 ; i <= M; ++ i) { if (Q[i].Left == Q[i].Right ) printf ("0/1\n") ; else { int K = GCD (Ans[i] , Sum[i]) ; Ans[i] /= K , Sum[i] /= K ; printf ("%lld/%lld\n" , Ans[i] , Sum[i]) ; } } fclose (stdin) , fclose (stdout) ; return 0 ; }
-
Thanks!