题意:
n[1,50],k[1,50],p[1e8,1e9].
求有多少 1 到 n 的排列满足:将前 k 个的数排列以后,最长上升子序列长度为 n−1 以上。
瞎搞:
用next_permutation打表,然后肉眼找出规律。
打表代码。
#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
//#define pa pair<int, int>
// const int maxn = 1e6+5;
int a[100], b[100];
int lis(int b[], int n) {
int *d = new int[n];
int len = 1;
for (int i = 0; i < n; i++) {
d[i] = 1;
for (int j = 0; j < i; j++) {
if (b[j] <= b[i] && d[j] + 1 >= d[i]) {
d[i] = d[j] + 1;
}
}
len = max(len, d[i]);
}
delete[] d;
return len;
}
int db(int n, int m) {
vector<int> v;
for (int i = 0; i < n; i++) {
a[i] = i + 1;
}
int cnt = 0;
do {
for (int i = 0; i < n; i++) b[i] = a[i];
sort(b, b + m);
int len = lis(b, n);
if (len + 1 >= n) cnt++;
} while (next_permutation(a, a + n));
return cnt;
}
int main() {
for (int n = 1; n < 10; n++) {
for (int m = 1; m <= n; m++) {
cout << n << ' ' << m << " " << db(n, m) << endl;
}
cout << endl;
}
int a;
cin >> a;
}
公式乱搞:
#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
ll mod;
ll jiecheng[60];
void db() {
jiecheng[0] = jiecheng[1] = 1;
for (int i = 2; i < 55; i++) {
jiecheng[i] = jiecheng[i - 1] * i % mod;
}
}
int main() {
int T, cas = 0;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k >> mod;
k = min(n, k);
db();
cout << "Case #" << ++cas << ": ";
ll ans = jiecheng[k];
ll add = (jiecheng[k + 1] - jiecheng[k] + mod) % mod;
ll add2 = jiecheng[k] * 2 % mod;
for (int i = k + 1; i <= n; i++) {
ans = (ans + add) % mod;
add = (add + add2) % mod;
}
cout << ans << endl;
}
}
正解:
题解:前k个排序之后分四种情况讨论:
1. 排序之后整个就有序了:k!
2. 排序之后前面是 1 到 k,后面最长上升子序列的长度是 n−k−1:k!⋅(n−k−1)^2。
3. 排序之后前 k 个数里有一个被换成了 k+1,被换的那个数可以插到后面里面去:k!⋅k(n−k)。
4. 排序之后前 k 个数里有一个(只能是 k)被换成了 k+2 以上的数,后面 n−k 个数必须有序:k!⋅(n−k−1)。
综上,答案就是 k!(1+(n−k−1)2+k(n−k)+(n−k−1))。
FROM:https://acm.ecnu.edu.cn/wiki/index.php?title=2018_ACM-ICPC_Shenyang_Regional_Onsite
代码:
#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
//#define pa pair<int, int>
const int maxn = 1e5 + 5;
ll mod;
ll jiecheng[60];
next_permutation
void db() {
jiecheng[0] = jiecheng[1] = 1;
for (int i = 2; i < 55; i++) {
jiecheng[i] = jiecheng[i - 1] * i % mod;
}
}
int main() {
int T, cas = 0;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k >> mod;
k = min(n, k);
db();
cout << "Case #" << ++cas << ": ";
ll ans = jiecheng[k] *
(1 + (n - k - 1) * (n - k - 1) + k * (n - k) + (n - k - 1)) % mod;
cout << ans << endl;
}
}