水题大战Vol.3 B. DP搬运工2

水题大战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;
}

原文地址:https://www.cnblogs.com/liuchanglc/p/13498358.html