BZOJ 4517 淺談錯位排列組合計數
阿新 • • 發佈:2019-02-17
世界真的很大
講道理本來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
*/
嗯,就是這樣