zoukankan      html  css  js  c++  java
  • P3813 [FJOI2017]矩阵填数(组合数学)

    P3813 [FJOI2017]矩阵填数

    shadowice1984说:看到计数想容斥........

    这题中,我们把图分成若干块,每块的最大值域不同

    蓝后根据乘法原理把每块的方案数(互不相干)相乘。

    怎么计算每块方案数呢

    把子矩阵按最大值从小到大排序

    暴力预处理好每$k(1<=k<=n)$个矩阵之间的交集、并集

    设最大值为$v$的位置的集合大小为$S$

    那么我们算出来(本层)的结果就是v^{|S|}

    然鹅我们并没有减去某些矩阵没有到最大值(最大只取到$v-1$)的情况

    于是对于每个最大值为$v$的子矩阵在$S$中的部分$T$,我们要减去$(v-1)^{|T|}*v^{|S-T|}$

    但是我们又发现,多减去了某2个子矩阵都没有到最大值的情况,于是我们就把它加起来

    再减去3个子矩阵都没到最大值的情况

    .............

    这就是容斥原理辣

    “最大值为$v$的位置的集合大小为$S$”,这个咋算呢

    $|S|=($最大值$<=v$的位置的集合大小)$-$(最大值$<v$的集合大小),$T$同理。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    inline ll Min(ll a,ll b){return a<b?a:b;}
    inline ll Max(ll a,ll b){return a>b?a:b;}
    ll Pow(ll x,ll y){
        ll re=1;
        for(;y;y>>=1,x=x*x%mod)
            if(y&1) re=re*x%mod;
        return re;
    }
    struct Matrix{
        ll xl,yl,xr,yr,v;
        bool operator < (const Matrix &tmp) const{return v<tmp.v;}
        void operator &= (const Matrix &tmp) {
            xl=Max(xl,tmp.xl), xr=Min(xr,tmp.xr);
            yl=Max(yl,tmp.yl), yr=Min(yr,tmp.yr);
        }
        inline void init(){
            scanf("%lld%lld%lld%lld%lld",&xl,&yl,&xr,&yr,&v);
        }
        inline bool null(){return xl>xr||yl>yr;}
        inline ll area(){return (xr-xl+1)*(yr-yl+1);}
    }a[20],p;
    int T,m,n,uni[2050],ist[2050],siz[2050];ll h,w;
    void Solve(){
        memset(uni,0,sizeof(uni));
        scanf("%lld%lld%d%d",&h,&w,&m,&n);
        for(int i=0;i<n;++i) a[i].init();
        sort(a,a+n); int Mx=(1<<n)-1;
        for(int i=1;i<=Mx;++i){//暴力处理交集
            p.xl=1;p.yl=1;p.xr=h;p.yr=w;
            for(int j=0,u=i;!p.null()&&u;u>>=1,++j)
                if(u&1) p&=a[j];
            ist[i]=p.null()?0:p.area();
        }
        for(int i=1;i<=Mx;++i)//暴力处理并集
            for(int j=i;j;j=(j-1)&i)
                uni[i]+=((siz[j]&1)?1:-1)*ist[j];
        int nw=0,ls=0;
        ll sum,tot,re,k,ans=Pow(m,h*w-uni[Mx]);
        for(int i=0;i<n;++i){//分层处理最大值为$a[i].v$的块的方案数
            nw|=(1<<i);
            if(a[i].v==a[i+1].v) continue;
            sum=uni[nw|ls]-uni[ls];
            re=Pow(a[i].v,sum);
            for(int u=nw;u;u=(u-1)&nw){
                tot=uni[u|ls]-uni[ls];
                k=Pow(a[i].v-1,tot)*Pow(a[i].v,sum-tot)%mod;
                if(siz[u]&1) re=(re-k+mod)%mod;
                else re=(re+k)%mod;
            }ans=ans*re%mod; ls|=nw; nw=0;
        }printf("%lld
    ",ans);
    }
    int main(){
        for(int i=1;i<=1023;++i) siz[i]=siz[i>>1]+(i&1);
        scanf("%d",&T);
        while(T--) Solve();
        return 0;
    }
  • 相关阅读:
    【Language】 TIOBE Programming Community Index for February 2013
    【diary】good health, good code
    【web】a little bug of cnblog
    【Git】git bush 常用命令
    【web】Baidu zone ,let the world know you
    【diary】help others ,help yourself ,coding is happiness
    【Git】Chinese messy code in widows git log
    【windows】add some font into computer
    SqlServer启动参数配置
    关于sqlserver中xml数据的操作
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10631980.html
Copyright © 2011-2022 走看看