• 【BZOJ1227】虔诚的墓主人(SDOI2009)-线段树+离散化+组合数


    测试地址:虔诚的墓主人
    做法:本题需要用到线段树+离散化+组合数。
    首先我们可以先将常青树的横纵坐标离散化,可是能成为十字架中心的墓地数量还是可能有W2个,这要怎么办呢?
    我们可以从下到上对于每一行,维护十字架中心在这一行的一段连续的墓地中的贡献。注意到我们要求的是:
    Cupk×Cdownk×Cleftk×Crightk
    在同一段连续的墓地中,leftright都相同,那么我们只需要统计这一段中Cupk×Cdownk的和就可以了。因为我们从下到上枚举行,所以可能会有单点修改的情况,而单点修改区间求和显然可以用线段树或树状数组来做,这里为了练手就写了线段树。
    因为点的数量只有W,所以上面的连续段的数量也是W的数量级,至于组合数可以O(Wk)预处理出来,那么总的复杂度就是O(WlogW),可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=(ll)2147483647+(ll)1;
    int n,m,w,k,tot0,tot,totx[100010]={0},toty[100010]={0},down[100010]={0};
    ll C[100010][11]={0},seg[400010]={0};
    struct point
    {
        int now,a,b;
    }p[100010];
    
    bool cmp1(point a,point b)
    {
        if (a.a!=b.a) return a.a<b.a;
        return a.b<b.b;
    }
    
    bool cmp2(point a,point b)
    {
        if (a.b!=b.b) return a.b<b.b;
        return a.a<b.a;
    }
    
    void init()
    {
        scanf("%d%d%d",&n,&m,&w);
        for(int i=1;i<=w;i++)
            scanf("%d%d",&p[i].a,&p[i].b);
        scanf("%d",&k);
    
        sort(p+1,p+w+1,cmp1);
        tot0=0;
        for(int i=1;i<=w;i++)
        {
            if (i==1||p[i].a!=p[i-1].a) ++tot0;
            p[i].now=tot0;
        }
        for(int i=1;i<=w;i++)
            p[i].a=p[i].now;
    
        sort(p+1,p+w+1,cmp2);
        tot=0;
        for(int i=1;i<=w;i++)
        {
            if (i==1||p[i].b!=p[i-1].b) ++tot;
            p[i].now=tot;
        }
        for(int i=1;i<=w;i++)
        {
            p[i].b=p[i].now;
            totx[p[i].a]++,toty[p[i].b]++;
        }
    
        C[0][0]=1;
        for(int i=1;i<=w;i++)
        {
            C[i][0]=1;
            for(int j=1;j<=k;j++)
                C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
    
    void pushup(int no)
    {
        seg[no]=seg[no<<1]+seg[no<<1|1];
    }
    
    void modify(int no,int l,int r,int x,ll d)
    {
        if (l==r) {seg[no]=d;return;}
        int mid=(l+r)>>1;
        if (x<=mid) modify(no<<1,l,mid,x,d);
        else modify(no<<1|1,mid+1,r,x,d);
        pushup(no);
    }
    
    ll query(int no,int l,int r,int s,int t)
    {
        if (s>t) return 0;
        if (l>=s&&r<=t) return seg[no];
        ll ans=0;
        int mid=(l+r)>>1;
        if (s<=mid) ans=(ans+query(no<<1,l,mid,s,t))%mod;
        if (t>mid) ans=(ans+query(no<<1|1,mid+1,r,s,t))%mod;
        return ans;
    }
    
    void work()
    {
        ll ans=0;
        int nowx=0;
        for(int i=1;i<=tot;i++)
        {
            int lft=0,last=0;
            for(int j=nowx+1;j<=nowx+toty[i];j++)
            {
                ans=(ans+C[lft][k]*C[toty[i]-lft][k]%mod*query(1,1,tot0,last+1,p[j].a-1)%mod)%mod;
                down[p[j].a]++;
                modify(1,1,tot0,p[j].a,C[down[p[j].a]][k]*C[totx[p[j].a]-down[p[j].a]][k]%mod);
                last=p[j].a;
                lft++;
            }
            nowx+=toty[i];
        }
        printf("%lld",ans);
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    css自适应浏览器大小
    javascript es6 箭头函数
    vue-router路由的使用
    vue-client脚手架使用
    springboot整合thymeleaf模板引擎
    SpringBoot不使用模板引擎直接返回html
    css加载动画
    java将数据从List转换Map
    KMP算法理解
    解决Linux服务器tomact-8.0启动慢的问题
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793503.html
Copyright © 2020-2023  润新知