题解:[ARC093F] Dark Horse
AT_arc093_d
题目描述
给定
具体解释,你是
题目分析
由于不管
令集合
它所遇见对手的情况无非是
把这些人分别用
发现
如果真的要这样就太复杂了
那我们反过来 ,考虑容斥 ,定义函数
现在来考虑
- 不选第
i 个数 ,dp[i][S]\rightarrow dp[i+1][S] - 选了第
i 个数 , 此时我们要去找S 中有0 的位置j , 把它填成a_i 。j 对应b_j ,不难分析 ,b_j 应该是由2^j 个数字取min 得到 , 一个位置填a_i , 剩下2^j-1 个位置都应该取比a_i 大且没有被选的数 ( 规则是这样说的 ) ,故有以下转移 :
for(int j=0;j<n;j++)
{
if(!((S>>j)&1))
{
les=(1<<n)-a[i]-S;
dp[i+1][S|(1<<j)]+=dp[i][j]*C(les,(1<<j)-1));
}
}
其中
code
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
const int N=20,K=(1<<16)+7,p=1e9+7;
int n,m;
int a[N];
ll dp[N][K],ans;
ll fac[K],inv[K];
ll qpow(ll x,int n,ll res=1)
{
while(n)
{
if(n&1) res=res*x%p;
x=x*x%p;
n>>=1;
}
return res;
}
bool cmp(int a,int b)
{
return a>b;
}
void init(int n)
{
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%p;
inv[n]=qpow(fac[n],p-2);
for(int i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%p;
}
ll C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%p*inv[n-m]%p;
}
int get_cnt(int x,int ans=0)
{
while(x)
{
ans++;
x-=lowbit(x);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);init(1<<n);
for(int i=1;i<=m;i++) scanf("%d",&a[i]);
sort(a+1,a+m+1,cmp);
dp[0][0]=1;
for(int i=0;i<m;i++)
{
for(int j=0;j<(1<<n);j++)
{
int t=(1<<n)-a[i+1]-j;
dp[i+1][j]=(dp[i+1][j]+dp[i][j])%p;
for(int k=0;k<n;k++)
{
if(!((j>>k)&1))
{
dp[i+1][j|(1<<k)]=(dp[i+1][j|(1<<k)]+dp[i][j]*C(t,(1<<k)-1)%p*fac[1<<k]%p)%p;
}
}
}
}
int S=(1<<n)-1;
for(int i=0;i<=S;i++)
{
int cnt=get_cnt(i);
if(cnt&1) ans=(ans-dp[m][i]*fac[S-i]%p+p)%p;
else ans=(ans+dp[m][i]*fac[S-i]%p)%p;
}
ans=ans*(S+1)%p;
printf("%d",ans);
return 0;
}
是不是发现最后