zoukankan      html  css  js  c++  java
  • bzoj 2038 [2009国家集训队]小Z的袜子(hose)

    这道题的概率求解最难算的就是求出能取到多少对多少颜色相同的袜子

    因为询问次数过多,这里不能一个个求解询问,需要将询问分块后访问

    先这么理解:

    令cnt[i] 表示 颜色 i 在当前的 l ~ r 的区域内出现的次数 , 此时颜色相同的袜子对数为 tmp

    比如说此时 r 向前一步到r+1 , 那么此时除了val[r+1]这个颜色的袜子数量+1了,其他颜色的袜子颜色是不会变化的,所以总的相同颜色的袜子的对数只要计算val[r+1]这个颜色就可以了

    那么在向前一步之前,val[r+1]这个颜色的可组成一对袜子的总数为 cnt[val[r+1]]*(cnt[val[r+1]]-1) , 之后是cnt[val[r+1]]*(cnt[val[r+1]]+1)

    所以tmp 就是 tmp = tmp - cnt[val[r+1]]*(cnt[val[r+1]]-1) + cnt[val[r+1]]*(cnt[val[r+1]]+1)

    r往后走,或者l往前往后走一样的方式思考

    那么我们主要考虑的就是 l ,r 指针移动的次数,我们总希望能将这样的询问排成一个合理序列,那么访问的时候 l , r 指针可以尽可能的少移动

    [l , r] -> [l',r'] 指针移动次数就是 abs(l-l') + abs(r-r');

    那么其实这里我们就相当于类似希望求出一个以曼哈顿距离为边的最小生成树,这就是莫队算法的思想

    但我实在看不懂这个生成树的形成方式,而且代码太长了,就用下方的复杂度略为高一点的方法了

    这里先将袜子的总数量分成 unit = sqrt(n) 个块 , l/unit 越小说明当前l所处的块越前面,所以我们逐个块处理,在每个块中,l的移动不会超过sqrt(n) , 令r在前面块层次相等时,再由小到大排列,这样就尽可能的让 r 指针少做移动

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cmath>
     6 using namespace std;
     7 #define ll long long
     8 #define N 50010
     9 int val[N] , unit , cnt[N];
    10 ll t[2][N];
    11 struct Query{
    12     int l , r , id ;
    13     Query(int l=0 , int r=0 , int id=0):l(l),r(r),id(id){}
    14 }q[N];
    15 
    16 bool cmp(Query a , Query b)
    17 {
    18     if(a.l/unit == b.l/unit) return a.r<b.r;
    19     return a.l/unit < b.l/unit;
    20 }
    21 
    22 ll gcd(ll a , ll b)
    23 {
    24     if(b == 0) return a;
    25     else return gcd(b , a%b);
    26 }
    27 
    28 void solve(int n , int m)
    29 {
    30     memset(cnt , 0 , sizeof(cnt));
    31     int l=1 , r=1 ;
    32     ll tmp=0;
    33     cnt[val[1]]++;
    34     for(int i=1 ; i<=m ; i++){
    35         while(r<q[i].r){
    36             r++;
    37             tmp -= (ll)cnt[val[r]]*(cnt[val[r]]-1);
    38             cnt[val[r]]++;
    39             tmp += (ll)cnt[val[r]]*(cnt[val[r]]-1);
    40         }
    41         while(r>q[i].r){
    42             tmp  -= (ll)cnt[val[r]]*(cnt[val[r]]-1);
    43             cnt[val[r]]--;
    44             tmp += (ll)cnt[val[r]]*(cnt[val[r]]-1);
    45             r--;
    46         }
    47         while(l<q[i].l){
    48             tmp -= (ll)cnt[val[l]]*(cnt[val[l]]-1);
    49             cnt[val[l]]--;
    50             tmp += (ll)cnt[val[l]]*(cnt[val[l]]-1);
    51             l++;
    52         }
    53         while(l>q[i].l){
    54             l--;
    55             tmp  -= (ll)cnt[val[l]]*(cnt[val[l]]-1);
    56             cnt[val[l]]++;
    57             tmp += (ll)cnt[val[l]]*(cnt[val[l]]-1);
    58         }
    59         t[0][q[i].id] = tmp;
    60         t[1][q[i].id] = (ll)(q[i].r-q[i].l)*(q[i].r-q[i].l+1);
    61     }
    62 }
    63 
    64 int main()
    65 {
    66   //  freopen("a.in" , "r" , stdin);
    67     int n , m;
    68     while(~scanf("%d%d" , &n , &m))
    69     {
    70         for(int i=1 ; i<=n ; i++) scanf("%d" , &val[i]);
    71         for(int i=1 ; i<=m ; i++){
    72             scanf("%d%d" , &q[i].l , &q[i].r);
    73             q[i].id=i;
    74         }
    75         unit = (int)sqrt(n+0.5);
    76         sort(q+1 , q+1+m , cmp);
    77 
    78         solve(n , m);
    79 
    80         for(int i=1 ; i<=m ; i++){
    81             if(t[0][i] == 0) t[1][i]=1;
    82             else{
    83                 ll k=gcd(t[0][i] , t[1][i]);
    84                 t[0][i]/=k,t[1][i]/=k;
    85             }
    86             printf("%lld/%lld
    " , t[0][i] , t[1][i]);
    87         }
    88     }
    89     return 0;
    90 }
  • 相关阅读:
    3.2 Program Encodings 程序编码
    Describe your home
    Building vs solution in command line
    找到适合自己的人生轨迹 Angkor:
    每个月总有那么几天不想学习,不想写代码 Angkor:
    Linux下的Memcache安装
    敏捷开发之 12条敏捷原则
    为什么要用NIO
    memcached server LRU 深入分析
    Linux 脚本编写基础
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4430473.html
Copyright © 2011-2022 走看看