[题解] 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!

posted @ 2019-04-29 17:46  Betulaceae  阅读(138)  评论(0编辑  收藏  举报