Iahub is so happy about inventing bubble sort graphs that he's staying all day long at the office and writing permutations. Iahubina is angry that she is no more important for Iahub. When Iahub goes away, Iahubina comes to his office and sabotage his research work.
The girl finds an important permutation for the research. The permutation contains n distinct integers a1, a2, ..., an (1 ≤ ai ≤ n). She replaces some of permutation elements with -1 value as a revenge.
When Iahub finds out his important permutation is broken, he tries to recover it. The only thing he remembers about the permutation is it didn't have any fixed point. A fixed point for a permutation is an element ak which has value equal to k (ak = k). Your job is to proof to Iahub that trying to recover it is not a good idea. Output the number of permutations which could be originally Iahub's important permutation, modulo 1000000007 (109 + 7).
The first line contains integer n (2 ≤ n ≤ 2000). On the second line, there are n integers, representing Iahub's important permutation after Iahubina replaces some values with -1.
It's guaranteed that there are no fixed points in the given permutation. Also, the given sequence contains at least two numbers -1 and each positive number occurs in the sequence at most once. It's guaranteed that there is at least one suitable permutation.
Output a single integer, the number of ways Iahub could recover his permutation, modulo 1000000007 (109 + 7).
5 -1 -1 4 3 -1
2
For the first test example there are two permutations with no fixed points are [2, 5, 4, 3, 1] and [5, 1, 4, 3, 2]. Any other permutation would have at least one fixed point.
-1 -1 4 3 -1
5
-1 -1 2 5 -1
顯然所有已經填好的位置可以不管,我們只看 a[i] = -1 的位置。
x 表示目前有多少個位置使得a[i] = -1 且數字 i 已經被填在某個位置上,稱為無限制位置。
y 表示目前有多少個位置使得a[i] = -1 且數字 i 沒有被填在某個位置上,稱為有限制位置。
那麼,最一開始的時候,我們先把 y 個有限制位置拋棄不看。
因為a[i] = -1 且 i 也沒有出現在任何位置上,所以忽略不看不會有影響。
現在我們先把 x 個無限制的位置填好。
由於有 x 個數的 a[i] = -1 但是數字 i 已經被使用了。所以也一定有 x 個數的a[i] != -1但是數字 i 還沒被用。
就把這 x 個沒使用的數字放在 x 個被填的位置上。方法數是 x! 。
現在我們把 y 個無限制的位置一個接一個的加進來
用 d[i] 表示已經有多少個無限制的位置被加進來,且不違反錯排的規則。
顯然d[0] = x ! 。我們所要求的就是d[y].
前面都比較好理解,主要就是下面這一部分,比較難理解了。
為了更好的理解,我拿個例子輔助說明。
如果此時我們把第 i 個有限制的位置加進來。分以下幾種情況:
1)我們從 x 個無限制的的位置中找一個 j ,令a[i] = a[j],a[j] = i。規約到d[i - 1]的方案數。
-1 -1 2 5 -1
2)我們從i - 1個有限制的位置中找一個位置 j ,令a[i] = j,a[j] = i。規約到d[i - 2]的方案數。
-1 -1 3 4 -1
3)我們從i - 1個有限制的位置中找一個位置 j ,令a[i] = j,但是a[j] != i。規約到d[i - 1]的方案數。也就相當於由原來的 d[j] != j 限制變為了d[j] != i,其它限制不變。
-1 -1 3 4 -1
AC程式碼:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
int mod=1e9+7;
__int64 d[2002];
int a[2002];
__int64 cal(int p)
{
__int64 ans=1;
int i;
for(i=2;i<=p;i++)
ans=(ans*i)%mod;
return ans;
}
int main()
{
int n,x,y;
while(~scanf("%d",&n))
{
int cnt=0,t=0; //cnt記錄可以填的個數,t記錄填的數字被佔用的個數
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==-1)
cnt++;
}
for(int i=1;i<=n;i++)
{
if(a[i]>0)
{
if(a[a[i]]==-1)
t++;
}
}
x=t; //x是無限制的個數
y=cnt-t;
d[0]=cal(x); //d[0]=x!
for(int i=1;i<=y;i++)
{
d[i]=((x+i-1)*d[i-1])%mod;
if(i>1)
d[i]=(d[i]+(i-1)*d[i-2])%mod;
}
printf("%I64d\n",d[y]);
}
return 0;
}
/*
5
-1 -1 4 3 -1
5
-1 -1 4 -1 -1
5
-1 -1 2 5 -1
*/