• 男神zyh的青睐


    G 男神zyh的青睐

    这道题与普通的莫队不一样的地方是,普通的莫队是求一个\([l,r]\)区间里面的贡献,但是这道题需要求两个区间贡献之间的积。

    普通的莫队是二维的,对左端点进行分块,然后再在块内对右端点进行排序,复杂度为\(O(n^{\frac{3}{2}})\)

    但是本题的莫队是三维的,对左端点进行分块,然后再在块内对右端点进行分块,然后再在块内对时间 t 进行排序,可以证明当块的大小取\(n^{\frac{2}{3}}\)的时候,算法的总复杂度为\(O(n^{\frac{5}{3})}\)

    可以利用容斥原理,将原本是四维的莫队,降为三维,把\((r_1-l_1)\times(r_2-l_2)\)变为\((r_2-l_2)\times[1,r]-(r_2-l_2)\times[1,l_1-1]\)

    不过我也尝试了一下四维莫队的解法,复杂度为\(O(n^{\frac{7}{4}})\),大概是1e8,在经过亿点点优化之后,居然卡过去了。

    然后又学会了二维莫队的写法

    二维莫队也是通过容斥进行降维的

    如果用\(c(l,r)\)表示一段区间的贡献,那么我们的总贡献就是\(c_1(l_1,r_1)\times c_2(l_2,r_2)\),然后可以发现\(c()\)是线性变化的,因此可以利用容斥进行拆分,\(f(a)\)表示\(c(1,a)\)\(c_1(l_1,r_1)\times c_2(l_2,r_2)=[f_1(r_1)-f_1(l_1-1)]\times [f_2(r_2)-f_2(l_2-1)]\)

    \(=f_1(r_1)\times f_2(r_2)+f_1(l_1-1)\times f_2(l_2-1)-f_1(r_1)\times f_2(l_2-1)-f_2(r_2)\times f_1(l_1-1)\)

    这样,利用容斥,我们就成功地把这个莫队降成了二维的莫队,其实三维的莫队也是这样的降的....

    二维写法:

    // Created by CAD
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn=5e4+5;
    const int mod=1e9+7;
    int a[maxn],cnt[2][maxn],belo[maxn];
    struct query{
        int l,r,f,id;
        bool operator <(const query& q)const {
            return belo[l]!=belo[q.l]?(belo[l]<belo[q.l]):((belo[l]&1)?r<q.r:r>q.r);
        }
    }q[maxn<<2];
    ll now;
    int ans[maxn],d[maxn];
    inline void add(int &x,int i){
        (now+=cnt[i^1][x])%=mod;
        ++cnt[i][x];
    }
    inline void del(int &x,int i){
        (now-=cnt[i^1][x])%=mod;
        --cnt[i][x];
    }
    inline ll qpow(ll x,ll n){
        ll ans=1;
        while(n>0){
            if(n&1)
                ans=ans*x%mod;
            x=x*x%mod,n>>=1;
        }
        return ans;
    }
    
    int main() {
        int n,m;scanf("%d%d",&n,&m);
        int blo=pow(n,0.5);
        for(int i=1;i<=n;++i){
            scanf("%d",a+i);
            belo[i]=(i-1)/blo-1;
        }
        for(int i=1;i<=m;++i){
            int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            q[4*i-3]={r1,r2,1,i};
            q[4*i-2]={r1,l2-1,-1,i};
            q[4*i-1]={l1-1,r2,-1,i};
            q[4*i]={l1-1,l2-1,1,i};
            d[i]=1ll*(r2-l2+1)*(r1-l1+1)%mod;
        }
        sort(q+1,q+4*m+1);
        int l=0,r=0;
        for(int i=1;i<=4*m;++i){
            int ql=q[i].l,qr=q[i].r,qf=q[i].f;
            while(l<ql) add(a[++l],0);
            while(l>ql) del(a[l--],0);
            while(r<qr) add(a[++r],1);
            while(r>qr) del(a[r--],1);
    
            (ans[q[i].id]+=now*qf)%=mod;
        }
        for(int i=1;i<=m;++i)
            printf("%lld\n",1ll*(ans[i]+mod)%mod*qpow(d[i],mod-2)%mod);
        return 0;
    }
    

    三维写法:

    // Created by CAD
    #include <bits/stdc++.h>
    #define ll long long
    
    using namespace std;
    
    const int maxn=5e4+5;
    const int mod=1e9+7;
    int belo[maxn];
    struct query{
        int l,r,id,t;
        bool operator<(const query &q)const {
            return belo[l]!=belo[q.l]?(belo[l]<belo[q.l]):(belo[r]!=belo[q.r]?(belo[r]<belo[q.r]):(t<q.t));
        }
    }q[maxn<<1];
    int a[maxn],cnt1[maxn],cnt2[maxn],ans[maxn];
    ll now;
    ll d[maxn];
    inline void add(int x){
        now+=cnt1[a[x]];
        now%=mod;
        cnt2[a[x]]++;
    }
    inline void del(int x){
        now-=cnt1[a[x]];
        now%=mod;
        cnt2[a[x]]--;
    }
    inline void ad(int x){
        now+=cnt2[a[x]];
        now%=mod;
        cnt1[a[x]]++;
    }
    inline void de(int x){
        now-=cnt2[a[x]];
        now%=mod;
        cnt1[a[x]]--;
    }
    
    ll qpow(ll x,ll n){
        ll ans=1;
        while(n>0){
            if(n&1) ans=ans*x%mod;
            x=x*x%mod,n>>=1;
        }
        return ans;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m;cin>>n>>m;
        int blo=pow(n,2/3.0);
        for(int i=1;i<=n;++i){
            cin>>a[i];
            belo[i]=(i-1)/blo+1;
        }
        for(int i=1;i<=m;++i){
            int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;
            q[i*2-1]={l2,r2,-i,l1-1};
            q[i*2]={l2,r2,i,r1};
            d[i]=1ll*(r2-l2+1)*(r1-l1+1)%mod;
        }
        sort(q+1,q+2*m+1);
        int l=1,r=0,t=0;
        for(int i=1;i<=2*m;++i){
            int ql=q[i].l,qr=q[i].r,qt=q[i].t;
            while(l<ql) del(l++);
            while(l>ql) add(--l);
            while(r<qr) add(++r);
            while(r>qr) del(r--);
    
            while(t<qt) ad(++t);
            while(t>qt) de(t--);
    
            ans[abs(q[i].id)]+=q[i].id/abs(q[i].id)*now;
            ans[abs(q[i].id)]%=mod;
        }
        for(int i=1;i<=m;++i){
            cout<<1ll*(ans[i]+mod)%mod*qpow(d[i],mod-2)%mod<<endl;
        }
        return 0;
    }
    

    四维写法:

    // Created by CAD
    #include <bits/stdc++.h>
    
    #define ll long long
    using namespace std;
    
    const int maxn=5e4+5;
    const int mod=1e9+7;
    int belo[maxn];
    struct query{
        int p[4],id;
        bool operator<(const query &q)const {
            for(int i=0;i<3;++i)
                if(belo[p[i]]!=belo[q.p[i]]){
                    if(!i||belo[p[i-1]]&1)
                        return belo[p[i]]<belo[q.p[i]];
                    else
                        return belo[p[i]]>belo[q.p[i]];
                }
    
            if(belo[p[2]]&1)
                return p[3]<q.p[3];
            else return p[3]>q.p[3];
        }
    }q[maxn<<1];
    int a[maxn],cnt[2][maxn],ans[maxn];
    ll now;
    ll d[maxn];
    inline void add(int &x,int &i){
        now+=cnt[i^1][x];
        now%=mod;
        ++cnt[i][x];
    }
    inline void del(int &x,int &i){
        now-=cnt[i^1][x];
        now%=mod;
        --cnt[i][x];
    }
    
    inline ll qpow(ll x,ll n){
        ll ans=1;
        while(n>0){
            if(n&1) ans=ans*x%mod;
            x=x*x%mod,n>>=1;
        }
        return ans;
    }
    
    int main() {
        int n,m;scanf("%d%d",&n,&m);
        int blo=pow(n,0.74);
        for(int i=1;i<=n;++i){
            scanf("%d",a+i);
            belo[i]=(i-1)/blo+1;
        }
        for(int i=1;i<=m;++i){
            int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            q[i]={l1,r1,l2,r2,i};
            d[i]=1ll*(r2-l2+1)*(r1-l1+1)%mod;
        }
        sort(q+1,q+m+1);
        int p[4]={1,0,0,0};
        for(int i=1;i<=m;++i){
            for(int j=0;j<2;++j){
                int &l=p[j*2],&r=p[j*2+1];
                int &ql=q[i].p[j*2],&qr=q[i].p[j*2+1];
                while(l<ql) del(a[l++],j);
                while(l>ql) add(a[--l],j);
                while(r<qr) add(a[++r],j);
                while(r>qr) del(a[r--],j);
            }
            ans[q[i].id]=now;
        }
        for(int i=1;i<=m;++i)
            printf("%lld\n",1ll*(ans[i]+mod)%mod*qpow(d[i],mod-2)%mod);
        return 0;
    }
    
    CAD加油!欢迎跟我一起讨论学习算法,QQ:1401650042
  • 相关阅读:
    练习系列 5、求子数组的最大和
    练习系列 8、m进制转n进制(任意进制转换)
    bind1st/bind2nd与mem_fun组合使用的问题
    练习系列 4、异质链表
    幻方常规解法汇总
    练习系列 7、打印数据的二进制表示
    C++成员函数指针错误用法警示
    FreeBSD启动出现My unqualified host name unkown...Sleeping for retry...解决方案
    从DLL导出.a文件
    WIN7桌面无反应解决方案
  • 原文地址:https://www.cnblogs.com/cader/p/14710663.html
Copyright © 2020-2023  润新知