1. 程式人生 > >BZOJ 4517 淺談錯位排列組合計數

BZOJ 4517 淺談錯位排列組合計數

這裡寫圖片描述
世界真的很大
講道理本來5分鐘的水題卡了我半個小時一直RE
原因竟是因為cout?
改成printf就對了??EXM?

看題先:

description:

求有多少種長度為 n 的序列 A,滿足以下條件:
1 ~ n 這 n 個數在序列中各出現了一次
若第 i 個數 A[i] 的值為 i,則稱 i 是穩定的。序列恰好有 m 個數是穩定的
滿足條件的序列可能很多,序列數對 10^9+7 取模。

input:

第一行一個數 T,表示有 T 組資料。
接下來 T 行,每行兩個整數 n、m。
T=500000,n≤1000000,m≤1000000

output:

輸出 T 行,每行一個數,表示求出的序列數

題目要求有m個數穩定,那麼肯定是先列舉這m個數:C(n,m)
然後剩下的n-m個數不能在自己原先站的位置,只看順序的話就是錯排:
fi= (i-1) *(fi-1 +fi-2)
O(n)預處理錯排,階乘,階乘的逆元
O(1)求解

不是我題解水,是真的只有這麼一點了。。

完整程式碼:

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long dnt;

const dnt mod=1e9+7;

int n,m,T;
dnt f[4000010],saber[4000010],inv[2000010
]; void init(int N) { f[0]=1,f[1]=0,f[2]=1,saber[0]=1,inv[0]=inv[1]=1; for(int i=3;i<=N;i++) f[i]=(i-1)*((f[i-1]+f[i-2])%mod)%mod; for(int i=1;i<=N;i++) saber[i]=saber[i-1]*i%mod; for(int i=2;i<=N;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; for(int i=1;i<=N;i++) inv[i]=inv[i]*inv
[i-1]%mod; } dnt Misaka(int a,int b) { if(a<b) return 0; return saber[a]*inv[b]%mod*inv[a-b]%mod; } int main() { init(2000000); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); printf("%lld\n",Misaka(n,m) * f[n-m] %mod); } return 0; } /* Whoso pulleth out this sword from this stone and anvil is duly bor nKing of all England */

嗯,就是這樣