水题大战Vol.3 B. DP搬运工2
题目描述
给你(n,K),求有多少个(1)到(n) 的排列,恰好有(K)个数(i) 满足(a_{i-1},a_{i+1}) 都小于(a_i)。
输入格式
一行两个整数(n,K)。
输出格式
一行一个整数(ans)表示答案(mod 998244353)。
样例
样例输入1
4 1
样例输出1
16
样例输入2
10 3
样例输出2
1841152
数据范围与提示
对于 (25\%) 的测试点,(1 leq n,K leq 10);
对于 (50\%) 的测试点,(1 leq n,K leq 100);
对于 (100\%) 的测试点,(1 leq n,K leq 2000);
保证数据有梯度
分析
一道典型的计数(DP)题
我们设 (f[i][j]) 为考虑完 (1 - i) ,有 (j) 个位置满足要求的方案数
对于 (f[i-1][j]) 如果我们向序列中插入一个数 (i) 那么会有两种情况
1、新插入的(i)插入到原来满足要求的(j)个位置旁边或者数列的两端,此时满足要求的位置仍然是(j)个,方案数为((j+1) imes 2)
2、(i)插入到原数列的其它位置,此时满足要求的位置变为 (j+1) 个,方案数为 (i-(j+1) imes 2)
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mian main
const int maxn=2e3+5;
const int mod=998244353;
int n,k,f[maxn][maxn];
signed mian(){
scanf("%lld%lld",&n,&k);
f[1][0]=1,f[2][0]=2;
for(int i=3;i<=n;i++){
int m=min(k,i/2);
for(int j=0;j<=m;j++){
if(f[i-1][j]==0) continue;
int now=f[i-1][j];
int fa=(j+1)*2;
f[i][j]=(f[i][j]+f[i-1][j]*fa)%mod;
f[i][j+1]=(f[i][j+1]+f[i-1][j]*(i-fa))%mod;
}
}
printf("%lld
",f[n][k]);
return 0;
}