AtCoder Beginner Contest 172 E - NEQ
求满足下列条件的长度为 N N N且包含 [ 1 , M ] [1, M] [1,M]范围内整数的序列 A 1 , A 2 , ⋯ , A N A_1, A_2, \cdots, A_N A1,A2,⋯,AN及 B 1 , B 2 , ⋯ , B N B_1, B_2, \cdots, B_N B1,B2,⋯,BN组成的序列对数量。
条件① —— 保证序列A, B内所有数唯一 很好满足,接下来看条件② —— 序列A, B的对应位置的数不同。
显然要让对应位置的数不同情况会很复杂,但至多有 K K K个位置的数不同的情况却很容易求解,因为这等价于有 至少 N − K N-K N−K个位置的数相同。
设:
f ( K ) f(K) f(K):序列内各数唯一且至多有 K K K个对应位置的数不同(至少 N − K N-K N−K个对应位置的数相同)的情况数;
g ( K ) g(K) g(K):序列内各数唯一且恰有 K K K个特定的对应位置的数不同的情况数;
易得:
f ( N ) = ∑ K = 0 N ( N K ) g ( K ) f(N) =\sum_{K=0}^N \binom{N}{K}g(K) f(N)=K=0∑N(KN)g(K)根据二项式反演可得:
g ( N ) = ∑ K = 0 N ( − 1 ) N − K ( N K ) f ( K ) g(N) = \sum_{K=0}^N (-1)^{N-K} \binom{N}{K} f(K) g(N)=K=0∑N(−1)N−K(KN)f(K)则答案即为 g ( N ) 。 g(N)。 g(N)。
根据至少 N − K N-K N−K个对应位置的数相同,可知 f ( K ) = P M N − K × ( P M − N + K K ) 2 f(K) = P_M^{N-K} \times (P_{M-N+K}^K)^2 f(K)=PMN−K×(PM−N+KK)2
则最终答案如下:
g ( N ) = ∑ K = 0 N ( − 1 ) N − K ( N K ) P M N − K × ( P M − N + K K ) 2 g(N) = \sum_{K=0}^N (-1)^{N-K} \binom{N}{K} P_M^{N-K} \times (P_{M-N+K}^K)^2 g(N)=K=0∑N(−1)N−K(KN)PMN−K×(PM−N+KK)2
#include
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 5e5 + 10;
int N, M;
LL fact[maxn], fact_inv[maxn];
LL qpow(LL a, LL b)
{
LL res = 1;
a %= MOD;
while(b)
{
if(b & 1)
res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
void preprocess()
{
fact[0] = 1;
for(int i = 1; i <= M; i++)
fact[i] = fact[i-1] * i % MOD;
fact_inv[M] = qpow(fact[M], MOD - 2);
for(int i = M; i >= 1; i--)
fact_inv[i-1] = fact_inv[i] * i % MOD;
}
LL comb(int a, int b)
{
if(a < 0 || b < 0 || a < b)
return 0;
else
return fact[a] * fact_inv[b] % MOD * fact_inv[a-b] % MOD;
}
LL perm(int a, int b)
{
if(a < 0 || b < 0 || a < b)
return 0;
else
return fact[a] * fact_inv[a-b] % MOD;
}
int main()
{
scanf("%d %d", &N, &M);
preprocess();
LL ans = 0;
for(int K = 0; K <= N; K++)
ans = (ans + qpow(-1, N - K) * comb(N, K) % MOD * perm(M, N - K) % MOD * qpow(perm(M - N + K, K), 2) % MOD) % MOD;
printf("%lld\n", (ans % MOD + MOD) % MOD);
return 0;
}