• 《算法竞赛进阶指南》0x44分块 莫队算法 小Z的袜子


    题目链接:https://www.acwing.com/problem/content/description/253/

    题目给出一个序列和M次询问,问从[L,R]区间中取出颜色相同的袜子的概率,实际上就是计算组合数,由于询问的数量过于庞大,只能用离线的莫队算法进行求解。

    对询问进行分块,先按照l进行排序,进行分块之后对每个分块中的部分按照r进行排序,这样就使得一个块中的询问完成后右端点最多合计移动了N,左端点最多在sqrt(N)范围内移动,所以可以在O(N*sqrt(N))时间内求出所有的询问对应的值,在询问中需要设置询问的编号,因为之后需要对他进行排序。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<string.h>
    #include<math.h>
    using namespace std;
    const int maxn = 50010;
    typedef long long ll;
    struct node{
        int l,r,id;
    }query[maxn];
    ll Ans[maxn][2];
    int c[maxn],L[maxn],R[maxn];
    int num[maxn];
    int n,m;
    ll ans;
    bool cmp0(node& a,node& b){//按照l进行排序 
        return a.l<b.l || (a.l==b.l && a.r<b.r);
    }
    bool cmp1(node& a,node& b){//块内按照r进行排序 
        return a.r<b.r;
    }
    void work(int x,int c){
        ans-=(ll)num[x]*(num[x]-1);
        num[x]+=c;
        ans+=(ll)num[x]*(num[x]-1);
    }
    ll gcd(ll a,ll b){
        return b?gcd(b,a%b):a;
    }
    int main(){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)scanf("%d",&c[i]);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&query[i].l,&query[i].r);
            query[i].id=i;
        }
        sort(query+1,query+m+1,cmp0);
        int t=sqrt(m);
        for(int i=1;i<=t;i++){
            L[i]=(i-1)*t+1;
            R[i]=i*t;
        }
        if(R[t]<m){
            L[t+1]=R[t]+1;
            R[++t]=m;
        }
        for(int i=1;i<=t;i++){//分块内部按照r递增排序,使得每个分块內的查询时间复杂度是O(N) 
            sort(query+L[i],query+R[i]+1,cmp1);
        }
        
        for(int i=1;i<=t;i++){
            memset(num,0,sizeof(num));
            ans=0;
            int l=query[L[i]].l,r=query[L[i]].r;
            for(int j=l;j<=r;j++)work(c[j],1);//每个块中第一个单独考虑 
            Ans[query[L[i]].id][0]=ans;
            Ans[query[L[i]].id][1]=(ll)(r-l)*(r-l+1);
            ll g=gcd(Ans[query[L[i]].id][0],Ans[query[L[i]].id][1]);
            if(l==r){//只要不是两个都是0,gcd都不会是0 
                Ans[query[L[i]].id][0]=0;
                Ans[query[L[i]].id][1]=1;
            }else{
                Ans[query[L[i]].id][0]/=g;
                Ans[query[L[i]].id][1]/=g;
            }
            
            for(int j=L[i]+1;j<=R[i];j++){
                while(r<query[j].r)work(c[++r],1);
                while(r>query[j].r)work(c[r--],-1);
                while(l>query[j].l)work(c[--l],1);
                while(l<query[j].l)work(c[l++],-1);
                
                if(query[j].l==query[j].r){
                    Ans[query[j].id][0]=0;
                    Ans[query[j].id][1]=1;
                }else{
                    Ans[query[j].id][0]=ans;
                    Ans[query[j].id][1]=(ll)(r-l)*(r-l+1);
                    ll g=gcd(Ans[query[j].id][0],Ans[query[j].id][1]);
                    Ans[query[j].id][0]/=g;
                    Ans[query[j].id][1]/=g;
                }
            }
        }
        
        for(int i=1;i<=m;i++){
            printf("%lld/%lld
    ",Ans[i][0],Ans[i][1]);
        }
        return 0;
    }
    每一个不曾起舞的日子,都是对生命的辜负。
  • 相关阅读:

    模块
    18 安装kali系统
    17 部署靶机环境下
    16 部署靶机环境上
    15 部署win2003和IIS服务
    Spring详解(十一)----Bean 的作用域
    Spring详解(十)----使用@Configuration与@Bean注解装配Bean
    Spring详解(九)----Spring Bean的自动装配(基于注解的方式【推荐】)
    Spring详解(八)----Spring Bean的装配(基于注解的方式【推荐】)
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13356924.html
Copyright © 2020-2023  润新知