\(\text{Problem}:\)Positions in Permutations
\(\text{Solution}:\)
设 \(f_{i}\) 表示完美数恰好为 \(i\) 的排列数,\(g_{i}\) 表示钦定完美数为 \(i\) 的排列数,由二项式反演,有:
\[f_{i}=\sum\limits_{j=i}^{n}(-1)^{j-i}\binom{j}{i}g_{j} \]现在考虑求出 \(g\)。设 \(h_{i,j,0/1,0/1}\) 表示前 \(i\) 个位置有 \(j\) 个完美数,\(i\) 选/不选,\(i+1\) 选/不选的方案数,有转移:
- \(i=1\),边界条件 \(h_{1,0,0,0}=h_{1,1,0,1}=1\)。
- \(i=n\),去掉有关 \(i+1\) 的转移即可。
- \(1<i<n\),且 \(i\) 不是完美数,有:
- \(1<i<n\),且 \(i\) 是完美数,有:
显然 \(g_{j}=h_{n,j,0,0}+h_{n,j,1,0}\),故可以求出 \(f_{i}\),总时间复杂度 \(O(nm)\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=1010, Mod=1e9+7;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,m,h[N][N][2][2],g[N],fac[N+5],inv[N+5];
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=x*x%Mod) if(p&1) res=res*x%Mod; return res; }
inline int C(int x,int y) { if(x<y||x<0||y<0) return 0; return fac[x]*inv[x-y]%Mod*inv[y]%Mod; }
signed main()
{
fac[0]=1;
for(ri int i=1;i<=N;i++) fac[i]=fac[i-1]*i%Mod;
inv[N]=ksc(fac[N],Mod-2);
for(ri int i=N;i;i--) inv[i-1]=inv[i]*i%Mod;
n=read(), m=read();
h[1][0][0][0]=h[1][1][0][1]=1;
for(ri int i=2;i<=n;i++)
{
for(ri int j=0;j<=i;j++)
{
h[i][j][0][0]=(h[i][j][0][0]+h[i-1][j][0][0]+h[i-1][j][1][0])%Mod;
h[i][j][1][0]=(h[i][j][1][0]+h[i-1][j][0][1]+h[i-1][j][1][1])%Mod;
if(!j) continue;
h[i][j][0][0]=(h[i][j][0][0]+h[i-1][j-1][0][0])%Mod;
h[i][j][1][0]=(h[i][j][1][0]+h[i-1][j-1][0][1])%Mod;
if(i<n)
{
h[i][j][0][1]=(h[i][j][0][1]+h[i-1][j-1][0][0]+h[i-1][j-1][1][0])%Mod;
h[i][j][1][1]=(h[i][j][1][1]+h[i-1][j-1][0][1]+h[i-1][j-1][1][1])%Mod;
}
}
}
for(ri int i=0;i<=n;i++) g[i]=fac[n-i]*(h[n][i][0][0]+h[n][i][1][0])%Mod;
int ans=0;
for(ri int i=m;i<=n;i++)
{
int w=C(i,m)*g[i]%Mod;
if((i-m)&1) ans=(ans-w+Mod)%Mod;
else ans=(ans+w)%Mod;
}
printf("%lld\n",ans);
return 0;
}