​ACM-ICPC Shenyang Oniste 2018 C. Insertion Sort​

题目

问你 n 的全排列中,满足下面条件的排列有多少种。

前 k 个排序后,最长上升子序列长度至少为 n - 1。

分析

正解好像是推式子。

ACM-ICPC Shenyang Oniste 2018  C. Insertion Sort(打表找规律)_i++

不过我想不到,,,打了个表,发现 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);
}
}
}