题目:
LINK
题意:一个序列长度为 M, 每个数值在 [1, N], 问这个序列的最长上升子序列刚好
为N 的时候, 序列有多少种。
分析:
感谢kg2006的思路。
首先选取 N 个位置 S1,S2,S3 ….. SN。 设S1 之前的位置没有 1, S1 - S2 没有 2…
则有 S1 之前 S1-S2之间 … SN-1 - SN 之间的数都是有 N-1 中选择方案。 而 SN
之后位置均为 N种。 枚举 SN 的位置 Last, 可以知道
Ans =
∑(Last−1N−1)∗(N−1)Last−N∗NM−Last
Code:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxm = 500000 + 131;
const int maxn = 100000 + 131;
const LL MOD = 1e9 + 7;
LL Mjie[maxm], Inv[maxm], JieInv[maxm];
LL PowN[maxm], PowN_[maxm];
void INIT() {
Mjie[0] = Mjie[1] = 1;
Inv[1] = 1;
for(LL i = 2; i < maxm; ++i) {
Mjie[i] = Mjie[i-1] * i % MOD;
Inv[i] = (MOD - MOD / i) * Inv[MOD % i] % MOD;
}
JieInv[1] = JieInv[0] = 1;
for(LL i = 2; i < maxm; ++i)
JieInv[i] = JieInv[i-1] * Inv[i] % MOD;
}
int main() {
INIT();
int t;
LL m, n;
scanf("%d", &t);
while(t--) {
scanf("%lld%lld", &m, &n);
PowN_[0] = PowN[0] = 1;
for(LL i = 1; i < maxm; ++i) {
PowN[i] = PowN[i-1] * n % MOD;
PowN_[i] = PowN_[i-1] * (n-1) % MOD;
}
LL Ans = 0;
for(LL Last = m; Last >= n; Last--) {
LL temp = (Mjie[Last-1] * JieInv[n-1] % MOD) * JieInv[Last-n] % MOD;
temp = temp * PowN_[Last-n] % MOD;
temp = temp * PowN[m-Last] % MOD;
Ans =( Ans + temp ) % MOD;
}
printf("%lld\n", Ans);
}
}