ACM-ICPC Shenyang Oniste 2018 C. Insertion Sort(打表找规律)
原创
©著作权归作者所有:来自51CTO博客作者stormjing的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目
问你 n 的全排列中,满足下面条件的排列有多少种。
前 k 个排序后,最长上升子序列长度至少为 n - 1。
分析
正解好像是推式子。
不过我想不到,,,打了个表,发现 n 一定,k 增大时的序列,做差后是个等差数列。直接把上面找出来的表模拟下出来了。
打表
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define fuck(x) cout<<x<<endl
const int N = 1e3 + 10;
const int mod = 998244353;
vector<int> v;
int dp[100];
int f(int n, int k){
int res = 0;
do{
vector<int> vv;
vv = v;
sort(vv.begin(), vv.begin() + k);
int ans = 0;
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for(int i = 1; i < n; i++){
int mm = -1;
for (int j = 0; j < i; j++){
if(vv[j] < vv[i])
mm = max(mm, dp[j]);
}
dp[i] = max(0, mm) + 1;
ans = max(dp[i], ans);
}
if(ans >= n-1){
res++;
// for(auto x : v){
// printf("%d", x);
// }
// puts("");
}
} while (next_permutation(v.begin(), v.end()));
return res;
}
void cal(int x){
v.clear();
for(int i = 1; i <= x; i++){
v.push_back(i);
}
for(int i = 1; i <= x; i++){
printf("%d %d %d\n", x, i, f(x, i));
}
}
int main(){
int x;
scanf("%d", &x);
cal(x);
}
代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define fuck(x) cout<<x<<endl
const int N = 1e3 + 10;
const int mod = 998244353;
int t;
ll n, k, q;
ll fac[N];
ll f[N], g[N];
int main(){
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++){
scanf("%lld%lld%lld", &n, &k, &q);
printf("Case #%d: ", cas);
fac[0] = fac[1] = 1;
for(int i = 2; i < 55; i++){
fac[i] = fac[i - 1] * i % q;
}
f[1] = 2 % q; // 2 4 12 48
for(int i = 2; i < 55; i++){
f[i] = f[i - 1] * i % q;
}
for(int i = 1; i < 53; i++){
g[i] = (fac[i + 1] - fac[i] + q) % q;
}
if(k > n){
printf("%lld\n", fac[n]);
}else{
ll ans = fac[k];
ll base = g[k];
for (int i = k + 1; i <= n; i++){
ans = (ans + base + q) % q;
base = (base + f[k] + q) % q;
}
printf("%lld\n", ans);
}
}
}