P2154 [SDOI2009]虔诚的墓主人

略有一点点思维的题。

首先,如果一个点上,下,左,右分别有\(a,b,c,d\)棵树,那这个点的十字架方案为\(C_{a}^{k}C_{b}^{k}C_{c}^{k}C_{d}^{k}\)

按x坐标扫一遍,同时树状数组维护每个y坐标的\(C_{a}^{k}C_{b}^{k}\),直接统计答案。复杂度\(O(nlogn)\)

#include<bits/stdc++.h>
#define il inline
#define vd void
#define ll long long
#define mod 2147483648ll
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
ll x[100010],y[100010],uni_x[100010],uni_y[100010];
std::vector<ll>S[100010];
ll t[100010];
il vd inc(ll&x,ll y){x+=y;x%=mod;}
il vd update(ll x,ll y){while(x<uni_y[0])inc(t[x],y),x+=x&-x;}
il ll query(ll x){ll ret=0;while(x)ret+=t[x],x-=x&-x;return ret%mod;}
il ll Query(ll l,ll r){
    if(l>r)return 0;
    return (query(r)-query(l-1)+mod)%mod;
}
ll A[100010],B[100010],C[200010][11];
int main(){
#ifndef ONLINE_JUDGE
    freopen("2154.in","r",stdin);
    freopen("2154.out","w",stdout);
#endif
    gi(),gi();ll n=gi();
    for(ll i=1;i<=n;++i)x[i]=uni_x[i]=gi(),y[i]=uni_y[i]=gi();
    std::sort(uni_x+1,uni_x+n+1);std::sort(uni_y+1,uni_y+n+1);
    uni_x[0]=std::unique(uni_x+1,uni_x+n+1)-uni_x;
    uni_y[0]=std::unique(uni_y+1,uni_y+n+1)-uni_y;
    for(ll i=1;i<=n;++i)x[i]=std::lower_bound(uni_x+1,uni_x+uni_x[0],x[i])-uni_x,y[i]=std::lower_bound(uni_y+1,uni_y+uni_y[0],y[i])-uni_y;
    for(ll i=1;i<=n;++i)S[x[i]].push_back(y[i]);
    ll k=gi(),ans=0;
    for(ll i=1;i<=n;++i)++B[y[i]];
    C[0][0]=1;
    for(int i=1;i<=200000;++i){
        C[i][0]=1;
        for(int j=1;j<=i&&j<=k;++j)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    for(ll i=1;i<uni_x[0];++i){
        std::sort(S[i].begin(),S[i].end());
        for(ll j=0;j<S[i].size();++j){
            update(S[i][j],mod-C[A[S[i][j]]][k]*C[B[S[i][j]]][k]%mod);
            --B[S[i][j]];
            update(S[i][j],C[A[S[i][j]]][k]*C[B[S[i][j]]][k]%mod);
        }
        
        for(ll j=1;j<S[i].size();++j)ans+=C[j][k]*C[(ll)S[i].size()-j][k]%mod*Query(S[i][j-1]+1,S[i][j]-1)%mod;
        
        for(ll j=0;j<S[i].size();++j){
            update(S[i][j],mod-C[A[S[i][j]]][k]*C[B[S[i][j]]][k]%mod);
            ++A[S[i][j]];
            update(S[i][j],C[A[S[i][j]]][k]*C[B[S[i][j]]][k]%mod);
        }
        ans%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-10-17 22:16  菜狗xzz  阅读(185)  评论(0编辑  收藏  举报