Atcoder ARC093F : Dark Horse

传送门

题解:
建出二叉树,我们现在要让 m 个点不以最小值出现在从1出现的位置往上的 log n 棵子树中。

考虑容斥,记 f i 表示非法子树(子树中最小值为m中的一个)的状态。 我们从大到小转移很容易DP出 f ,然后就做完了。

#include <bits/stdc++.h>
using namespace std;

const int N=17, M=1<<N, mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}

int n,m,L,a[N],f[M],fac[M],ifac[M],sum[M],bin[N];
inline int C(int a,int b) {if(a<b) return 0; return mul(fac[a],mul(ifac[b],ifac[a-b]));}

int main() {
    cin>>n>>m; L=1<<n;
    for(int i=0;i<=n;i++) bin[i]=1<<i;
    for(int i=1;i<=m;i++) cin>>a[i];
    fac[0]=1; for(int i=1;i<=L;i++) fac[i]=mul(fac[i-1],i);
    ifac[L]=power(fac[L],mod-2); for(int i=L-1;~i;i--) ifac[i]=mul(ifac[i+1],i+1);
    sort(a+1,a+m+1);
    f[0]=1;
    for(int i=m;i>=1;i--) 
        for(int sta=(1<<n)-1;~sta;--sta)
            for(int j=0;j<n;j++) if(sta&bin[j]) 
                f[sta]=add(f[sta],mul(mul(f[sta^bin[j]],C(L-a[i]-sta+bin[j],bin[j]-1)),fac[bin[j]]));
    int ans=0;
    for(int i=0;i<(1<<n);++i) {
        int cur=mul(f[i],fac[L-i-1]);
        if(__builtin_popcount(i)&1) ans=dec(ans,cur);
        else ans=add(ans,cur);
    } cout<<mul(ans,L)<<'\n';
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/80877782