给你\(n,K\),求有多少个\(1\)到\(n\) 的排列,恰好有\(K\)个数\(i\) 满足\(a_{i-1},a_{i+1}\) 都小于\(a_i\)。
一行两个整数\(n,K\)。
一行一个整数\(ans\)表示答案\(mod 998244353\)。
4 1
16
10 3
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)\times 2\)
2、\(i\)插入到原数列的其它位置,此时满足要求的位置变为 \(j+1\) 个,方案数为 \(i-(j+1) \times 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\n",f[n][k]);
return 0;
}
原文:https://www.cnblogs.com/liuchanglc/p/13498358.html