ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【2022 省选训练赛 Contest 06 B】stat(DP)

2022-02-25 22:04:07  阅读:142  来源: 互联网

标签:分数 stat 排列 06 Contest int 最大值 然后 DP


stat

题目链接:2022 省选训练赛 Contest 06 B

题目大意

问你有多少对长度为 n 的排列的分数大于等于 k。
两个排列的分数是它们每一位取最大值的和。

思路

考虑固定一个排列按顺序,然后每个跟另外一个匹配,然后答案乘上排列的种数。

然后因为是最大值考虑从大往小 DP:
可以考虑每个数要贡献多少次(\(2,1,0\) 三种可能)
那如果你不当最大值,前面肯定要一个比它大的挡住,所以我们可以这样 DP:
\(f_{i,j,k}\) 为当前到位置 \(i\),前面能拿来挡的有 \(j\) 个,然后当前的分数是 \(k\)。

然后你就分三种情况转:
\(0\) 次:那两边都要被挡住,对面的数组各自都要选一个拿出来,所以要乘上 \(j*j\);然后挡的位置少了一个。
\(1\) 次:那要选一边挡住,或者它们两个自己配对,所以是 \(j+j+1\);能挡的位置其实每边,毕竟你少了一个有多了一个相当于没边。
\(2\) 次:不用挡;能拿来挡的位置多了一个。

代码

#include<cstdio>
#define ll long long
#define mo 1000000007

using namespace std;

int n, k;
ll f[72][72][5001];

int main() {
	scanf("%d %d", &n, &k);
	
	f[n + 1][0][0] = 1;
	for (int i = n + 1; i >= 2; i--) {
		for (int j = 0; j <= n - i + 1; j++)
			for (int k = 0; k <= 5000; k++)
				if (f[i][j][k]) {
					(f[i - 1][j + 1][k + (i - 1) + (i - 1)] += f[i][j][k]) %= mo;
					(f[i - 1][j][k + (i - 1)] += f[i][j][k] * (j + j + 1) % mo) %= mo;
					if (j) (f[i - 1][j - 1][k] += f[i][j][k] * j % mo * j % mo) %= mo;
				} 
	}
	ll ans = 0;
	for (int i = k; i <= 5000; i++) (ans += f[1][0][i]) %= mo;
	for (int i = 1; i <= n; i++) ans = ans * i % mo;
	printf("%lld", ans);
	
	return 0;
}

标签:分数,stat,排列,06,Contest,int,最大值,然后,DP
来源: https://www.cnblogs.com/Sakura-TJH/p/15937897.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有