C. Iahub and Permutationstime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard output
distinct integers a, a, ..., an ai ≤ n). She replaces some of permutation elements with -1 value as a revenge.
k 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 ( + 7).
Input
(n ≤ 2000). On the second line, there are n integers, representing Iahub's important permutation after Iahubina replaces some values with -1.
Output
Sample test(s)input
outputNote
-1 -1 4 3 -15
-1 -1 2 5 -1
開始看了傳說中的frog蛙神的部落格,表示看了一晚上都不解,若菜都是一把淚水啊!邊看邊問,終於理解了其中的要義,感謝frog1902的講解。題目地址:C. Iahub and Permutations
顯然所有已經填好的位置可以不管,我們只看 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 -15-1 -1 4 -1 -15-1 -1 2 5 -1*/