[数学记录]AT3981 [ARC093D] Dark Horse
command_block · · 个人记录
题意 :
有
你是第
- 给出
m 个人A_1 \sim A_m 。 - 这
m 个人都打得过你。 - 你打得过除了这
m 个人之外的所有其他人。 - 对于剩下的情况(你不参与的情况),编号小的人胜利。
问你在所有的
其中
其中下降幂可以预处理阶乘后快速计算。
边界 :
最终需要考虑剩余数的排列,有
复杂度
#include<algorithm>
#include<cstdio>
#define ll long long
#define MaxS 66000
using namespace std;
const int mod=1000000007;
ll powM(ll a,int t=mod-2){
ll ret=1;
while(t){
if (t&1)ret=ret*a%mod;
a=a*a%mod;t>>=1;
}return ret;
}
ll fac[MaxS],ifac[MaxS];
ll dpow(int k,int n)
{return k<n ? 0 : fac[k]*ifac[k-n]%mod;}
void Init(int n)
{
fac[0]=1;
for (int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
ifac[n]=powM(fac[n]);
for (int i=n;i;i--)
ifac[i-1]=ifac[i]*i%mod;
}
ll f[18][MaxS];
int cnt(int s){
int ret=0;
while(s){s^=s&-s;ret++;}
return ret;
}
int n,m,a[18];
int main()
{
scanf("%d%d",&n,&m);
int tot=1<<n;Init(tot);
for (int i=1;i<=m;i++)scanf("%d",&a[i]);
reverse(a+1,a+m+1);
f[0][0]=1;
for (int i=1;i<=m;i++)
for (int s=0;s<tot;s++){
f[i][s]=f[i-1][s];
for (int j=0;j<n;j++)
if (s&(1<<j))
f[i][s]=(f[i][s]+f[i-1][s^(1<<j)]*dpow(tot-a[i]-(s^(1<<j)),(1<<j)-1)%mod*(1<<j))%mod;
}
ll ans=0;
for (int s=0;s<tot;s++){
ll buf=f[m][s]*fac[tot-1-s]%mod;
if (cnt(s)&1)ans-=buf;else ans+=buf;
}ans=(ans%mod+mod)%mod;
printf("%lld",(ans<<n)%mod);
return 0;
}