1. 程式人生 > 實用技巧 >P4071 [SDOI2016]排列計數

P4071 [SDOI2016]排列計數

題目描述

求有多少種11到nn的排列aa,滿足序列恰好有mm個位置ii,使得a_i = iai=i。

答案對10^9 + 7109+7取模。

輸入格式

本題單測試點內有多組資料。

輸入的第一行是一個整數TT,代表測試資料的整數。

以下TT行,每行描述一組測試資料。

對於每組測試資料,每行輸入兩個整數,依次代表nn和mm。

輸出格式

共輸出TT行,對於每組測試資料,輸出一行一個整數代表答案。

輸入輸出樣例

輸入 #1
5
1 0
1 1
5 2
100 50
10000 5000
輸出 #1
0
1
20
578028887
60695423

說明/提示

資料規模與約定

本題共 20 個測試點,各測試點等分,其資料規模如下表。

測試點編號T =T=n, m \leqn,m測試點編號T =T=n, m \leqn,m
1\sim 313 10^3103 88 10 \sim 121012 10^3103 10^3103
4 \sim 646 10^3103 1212 13 \sim 141314 5 \times 10^55×105 10^3103
7 \sim 979 10^3103 100100 15 \sim 201520 5 \times 10^55×105 10^6106

對於全部的測試點,保證1 \leq T \leq 5 \times 10^51T5×105,1 \leq n \leq 10^61n106,0 \leq m \leq 10^60m106。

// 錯排模板題,f[i]為錯排
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 7;
typedef long long LL;
const LL MOD = 1e9 + 7;
LL f[MAXN], fac[MAXN];
void init() {
    f[1] = 0; f[2] = 1;
    for (int i = 3; i < MAXN; i++) f[i] = (i - 1) * (f[i - 1] + f[i - 2]) % MOD;
    fac[0] = 1;
    
for (int i = 1; i < MAXN; i++) fac[i] = (fac[i - 1] * i) % MOD; } LL ksm(LL a, LL b) { LL ans = 1; while (b) { if (b & 1) ans = ans * a % MOD; a = a * a % MOD; b >>= 1; } return ans; } LL inv(LL a) { return ksm(a, MOD - 2); } int main() { init(); int T, n, m; cin >> T; init(); while (T--) { scanf("%d%d", &n, &m); if (n == m) { printf("1\n"); continue; } LL ans = fac[n] * inv(fac[m]) % MOD * inv(fac[n - m]) % MOD * f[n - m] % MOD; printf("%lld\n", ans); } return 0; }