Description
给出一个排列 a1,...,an ,有一些位置是 −1 表示不确定,现要将这些不确定的位置填好使得整个排列没有不动点,问方案数
Input
第一行一整数
n
表示排列长度,之后输入
Output
输出合法方案数,结果模 109+7 ,保证至少有一组解
Sample Input
5
-1 -1 4 3 -1
Sample Output
2
Solution
把不确定位置分成两种:在排列中未出现过的(
x
个),在排列中出现过的(
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=2005;
#define mod 1000000007
int fact[maxn],inv[maxn];
void init(int n=2000)
{
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=(ll)i*fact[i-1]%mod;
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mod-(ll)(mod/i)*inv[mod%i]%mod;
inv[0]=1;
for(int i=1;i<=n;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
}
int C(int n,int m)
{
return (ll)fact[n]*inv[m]%mod*inv[n-m]%mod;
}
int n,a[maxn],vis[maxn],dp[maxn];
int main()
{
init();
while(~scanf("%d",&n))
{
memset(vis,0,sizeof(vis));
int x=0,y=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
vis[a[i]]=1;
if(a[i]==-1)y++;
}
for(int i=1;i<=n;i++)
if(!vis[i]&&a[i]==-1)x++;
y-=x;
dp[0]=fact[y];
for(int i=1;i<=x;i++)
{
dp[i]=fact[i+y];
for(int j=1;j<=i;j++)
{
dp[i]-=(ll)C(i,j)*dp[i-j]%mod;
if(dp[i]<0)dp[i]+=mod;
}
}
printf("%d\n",dp[x]);
}
return 0;
}