C. Insertion Sort
题意:给出
n
,
k
n,k
n,k,询问
n
n
n的全排列中,有多少个排列在给前
k
k
k个元素排完序后满足最长递增子序列长度大于等于
n
−
1
n-1
n−1。
题解:实际上好像是有公式的。但是我的做法比较蠢。打表肉眼找规律。可以发现当
k
k
k固定不变,
n
n
n递增的时候是有规律的。
代码
先贴一份打表的
int dp[100];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int T,n,k;
cin >> T;
vector<int> v;
while(T--) {
cin >> n >> k;
v.clear();
for(int i = 1; i <= n; ++i) {
v.push_back(i);
}
dbg(n,k);
int cnt = 0;
do{
vector<int> a = v;
sort(a.begin(),a.begin() + k);
for(int i = 1; i <= n; ++i) dp[i] = 1;
for(int i = 2; i <= n; ++i) {
for(int j = 1; j < i; ++j) {
if(a[i - 1] > a[j - 1]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
if((*max_element(dp + 1, dp + n + 1)) >= n - 1) cnt++;
}while(next_permutation(v.begin(),v.end()));
cout << cnt << '\n';
}
return 0;
}
然后是AC代码
typedef long long LL;
LL dp[100][100];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int mod,n,k;
int T,w = 0;
cin >> T;
while(T--) {
cin >> n >> k >> mod;
if(n < k) k = n;
dp[1][1] = 1;
dp[2][1] = 2;
for(int i = 2; i <= n; ++i) {
dp[i][i] = dp[i - 1][i - 1] * i % mod;
}
LL num = 2, sum = 0, last = 0;
for(int j = 1; j <= k; ++j) {
sum = (dp[j][j] + j * last % mod) % mod;
last = sum % mod;
num = num * j % mod;
for(int i = j + 1; i <= n; ++i) {
dp[i][j] = (dp[i - 1][j] % mod + sum % mod) % mod;
sum = (sum + num) % mod;
}
}
cout << "Case #" << ++w << ": " << dp[n][k] % mod << '\n';
}
return 0;
}