• 【BZOJ4487】[JSOI2015] 染色问题(高维容斥)


    点此看题面

    大致题意: 有一个(n*m)的矩形,先让你用(C)种颜色给它染色。每个格子可染色可不染色,但要求每行每列至少有一个小方格被染色,且每种颜色至少出现一次。求方案数。

    高维容斥

    显然题目中给你(3)个条件,而我们要一起容斥,所以就是高维容斥。。。

    通过高维容斥,我们可以得到这样一个式子:

    [sum_{i=0}^n(-1)^{n-i}C_n^isum_{j=0}^m(-1)^{m-j}C_m^jsum_{k=0}^c(-1)^{c-k}C_c^k(k+1)^{ij} ]

    然后我们把三个(sum)提前,就可以得到这样一个式子:

    [sum_{i=0}^nsum_{j=0}^msum_{k=0}^c(-1)^{n+m+c-i-j-k}C_n^iC_m^jC_c^k(k+1)^{ij} ]

    可以发现,这个式子可以(O(nmc))推,做这题(n,m,cle400)的数据已经足够了。

    二项式定理

    虽说原先的式子已经能水过了,但这题其实可以优化至(O(nclog_2m))

    首先我们要知道二项式定理是这样一个式子:

    [(x+y)^n=sum_{i=0}^nC_n^ix^iy^{n-i} ]

    然后我们就要考虑将上面的式子转化,使其能够用二项式定理化简:

    [sum_{i=0}^nsum_{k=0}^c((-1)^{n+m+c-i-k}C_n^iC_c^ksum_{j=0}^mC_m^j(-1)^{-j}((k+1)^i)^j) ]

    接下来我们单独考虑其中(sum_{j=0}^mC_m^j(-1)^{-j}((k+1)^i)^j)

    观察可得,这个式子中枚举上界为(m),有一个组合数(C_m^j),且(((k+1)^i)^j)一项为(j)次项,因此我们要把另一项变成((m-j))次项。

    也就是我们要乘上一个((-1)^m)

    于是就能得到这样一个式子:

    [(-1)^{-m}sum_{j=0}^mC_m^j(-1)^{m-j}((k+1)^i)^j ]

    [(-1)^{-m}(-1+(k+1)^i)^m ]

    考虑当(m)为奇数时,((-1)^{-m}=-1),可得:

    [(1-(k+1)^i)^m ]

    考虑当(m)为偶数时,((-1)^{-m}=-1),考虑到一个数与其相反数的偶次幂相等,可得:

    [(1-(k+1)^i)^m ]

    因此,原始可以简单地归纳为一个式子。

    再把这个式子代回整个式子中,就得到:

    [sum_{i=0}^nsum_{k=0}^c((-1)^{n+m+c-i-k}C_n^iC_c^k(1-(k+1)^i)^m ]

    而这个式子就可以(O(nclog_2m))求解了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 400
    #define X 1000000007
    #define Qinv(x) Qpow(x,X-2)
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    #define Dec(x,y) ((x-=(y))<0&&(x+=X))
    #define C(x,y) (1LL*Fac[x]*Inv[y]%X*Inv[(x)-(y)]%X)
    #define swap(x,y) (x^=y^=x^=y)
    using namespace std;
    int n,m,c,Fac[N+5],Inv[N+5];
    I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}//快速幂
    I int XSub(RI x,CI y) {return Dec(x,y),x;}//模意义下做减法
    int main()
    {
        RI i,k,t,ans=0;for(scanf("%d%d%d",&n,&m,&c),t=max(n,c),Fac[0]=i=1;i<=t;++i) Fac[i]=1LL*Fac[i-1]*i%X;//初始化阶乘
        for(Inv[t]=Qinv(Fac[t]),i=t-1;~i;--i) Inv[i]=1LL*Inv[i+1]*(i+1)%X;//初始化阶乘逆元
        for(i=0;i<=n;++i) for(k=0;k<=c;++k)//枚举i和k,求解答案
        {
            if((n+m+c-i-k)&1) Dec(ans,1LL*C(n,i)*C(c,k)%X*Qpow(XSub(1,Qpow(k+1,i)),m)%X);
            else Inc(ans,1LL*C(n,i)*C(c,k)%X*Qpow(XSub(1,Qpow(k+1,i)),m)%X);
        }
        return printf("%d",ans),0;//输出答案
    }
    
  • 相关阅读:
    .net com
    Json树递归Js查询Json父子节点
    Angular中使用$watch监听object属性值的变化
    教程
    JS格式化Thu May 12 2016 08:00:00 GMT+0800 (中国标准时间)
    js中获取时间new Date()详细介绍
    select默认空白问题。。
    angular先加载页面再执行事件,特别在动态生成id,然后做echarts等图表
    详解angularJs中自定义directive的数据交互
    Angularjs ng-table的使用(可以加button)以及angularjs学习资料
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4487.html
Copyright © 2020-2023  润新知