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

    这是个很奇怪的东西,不过有n*sqrt(n)的时间复杂度保证, 所以直接乱搞

    一个区间[l,r]内抽到同种颜色袜子的概率(设num[i]表示该区间中颜色为i的袜子数量)

                         sum( num[i])*(num[i]-1) ) / (r-l+1)*(r-l), (1<=i<=n)

    分母很容易求出来,我们单独考虑分子,上式化简为

                         (sum(num[i]*num[i]) - sum(num[i])) / (r-l+1)*(r-l)

    而sum([i])就是这个区间的长度, 所以我们只要先统计平方和,最后减去区间长度即可

    对于已知答案的区间[l,r],可以O(1)时间算出[l-1,r],[l,r+1],[l+1,r],[l,r-1]的答案(由于区间只改动了1,只有一种颜色数量改变,只要减去原来数量的平方,加上新的数量的平方)

    离线处理询问:先将n分成sqrt(n)块,然后先按每个询问的l所在块的编号从小到大排序,相同块按r排序(为什么这样,可能是因为相邻区间的l和r间就相差比较少,可以发挥上面性质的优点)

    然后再YY一下得到如下代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b) {
        return b?gcd(b,a%b):a;
    }
    int n,m,sum,sqn,pc[50007],c[50007],num[50007];
    ll ans;
    struct query{
        int l,r,id;
        ll a,b;
        inline void read(int i){scanf("%d%d",&l,&r);id=i;}
        bool operator < (const query& b)const{
            return pc[l]<pc[b.l]||(pc[l]==pc[b.l]&&r<b.r)||(pc[l]==pc[b.l]&&r==b.r&&l<b.l);
        }
    }Q[50007];
    bool cmp(const query& a,const query& b){return a.id<b.id;}
    int main() {
        scanf("%d%d",&n,&m);sqn=sqrt(n);
        for(int i=1,j=0;i<=n;i++){
            scanf("%d",&c[i]);
            if(i%sqn==1) j++; 
            pc[i]=j;
        }
        for(int i=1;i<=m;i++) Q[i].read(i);
        sort(Q+1,Q+m+1);
        int l=1,r=0;
        for(int i=1;i<=m;i++){
            int p=Q[i].l,q=Q[i].r;
            while(r<q)r++,num[c[r]]++,ans+=num[c[r]]*num[c[r]]-(num[c[r]]-1)*(num[c[r]]-1);
            while(l<p)ans+=(num[c[l]]-1)*(num[c[l]]-1)-num[c[l]]*num[c[l]],num[c[l]]--,l++;
            while(r>q)ans+=(num[c[r]]-1)*(num[c[r]]-1)-num[c[r]]*num[c[r]],num[c[r]]--,r--;
            while(l>p)l--,num[c[l]]++,ans+=num[c[l]]*num[c[l]]-(num[c[l]]-1)*(num[c[l]]-1);
            Q[i].a=ans-(q-p+1);Q[i].b=(ll)(q-p+1)*(q-p);
        }
        sort(Q+1,Q+m+1,cmp);
        for(int i=1;i<=m;i++) {
            ll Gcd=gcd(Q[i].a,Q[i].b);
            if(!Q[i].a) printf("0/1
    ");
            else printf("%lld/%lld
    ",Q[i].a/Gcd,Q[i].b/Gcd);
        }
        return 0;
    }
  • 相关阅读:
    ES基础(五十五)在私有云与公有云上管理与部署 Elasticsearch 集群
    ES基础(五十四)如何对集群进行容量规划
    ES基础(五十二)Hot & Warm 架构与 Shard Filtering
    ES基础(四十九)集群内部安全通信
    ES基础(四十八)集群身份认证与用户鉴权
    kata + docker run & star
    libcontainer nsexec + unshare + syscall(SYS_setns
    docker createHooks
    mount namespace
    exec.Command("/proc/self/exe", "child")
  • 原文地址:https://www.cnblogs.com/usingnamespace/p/5208372.html
Copyright © 2011-2022 走看看