首页 > 其他分享 >P8810 [蓝桥杯 2022 国 C] 数组个数 题解

P8810 [蓝桥杯 2022 国 C] 数组个数 题解

时间:2022-12-16 22:22:34浏览次数:42  
标签:return idx .. int 题解 蓝桥 2022 ans dp

思路比较简单的一道题。

用的五维 dp,看到二维和三维的 dp 直接膜了 orz。

正文开始。

分析

不难看出 dp。

因为 \(b_i\) 的值只与 \(a_{i-1},a_i,a_{i+1}\) 有关,所以我们定义 \(b_i\) 被 \(a_{c_1},a_{c_2},...a_{c_p}\) 满足为在这些 \(a\) 中最大的一项恰好为 \(b_i\)。

用 \(dp_{i,j,0/1,0/1,z}\) 来表示此状态下的方案数。

其中:

  • \(i\) 表示当前处于第 \(i\) 项。
  • \(j\) 表示当前这一项选择 \(j\)。
  • \(1/0\) 表示 \(b_i\) 是否被 \(a_{i-1},a_i\) 满足。
  • \(1/0\) 表示 \(b_0\) 是否被 \(a_0,a_1\) 满足。
  • \(z\) 表示 \(a_0\) 选择 \(z\)。

显然,\(a_i\) 的最大值就是 \(\min(b_{i-1},b_i,b_{i+1})\),又因为 \(b_i\le10\),所以 \(a_i\) 的最大值也是 \(10\)。

状态转移方程比较复杂。

如果 \(i>1\),那么我们需要枚举 \(a_i\) 和 \(a_{i-1}\)。

这时候存在两种情况:

  1. \(b_i\) 被 \(a_i,a_{i-1}\) 满足,此时应该更新 \(dp_{..,..,1,..,..}\) 的值。
  2. \(b_i\) 不被 \(a_i,a_{i-1}\) 满足,此时应该更新 \(dp_{..,..,0,..,..}\) 的值。

注意:在选择 \(a_i\) 的时候,\(b_{i-1}\) 必须被 \(a_{i-2},a_{i-1},a_i\) 满足,原因显然。

但当 \(i=1\) 时,应该单独讨论,因为 \(a_1\) 的选择会影响到 dp 数组的第 \(4\) 项,而 \(i\ge2\) 则不会。思路跟 \(i\ge2\) 的情况类似,不再赘述。

最后统计答案时,我们有几种情况:

  • \(dp_{n-1,x,1,1,y}\),因为此时 \(b_{n-1}\) 和 \(b_0\) 已经被满足,而其它的 \(b\) 也都被满足,直接加上即可。
  • \(dp_{n-1,x,0,1,y}\) 当 \(b_{n-1}\le y\) 时可以相加,因为 \(a\) 数组是环形的。
  • \(dp_{n-1,x,1,0,y}\) 当 \(b_0\le x\) 时可以相加,原因同上。

最后,记得取模。

AC Code

臭长臭长的代码 qwq。

#include <bits/stdc++.h>

using namespace std;

const int N = 1010;
const int MOD = 1e9 + 7;

int n;
int dp[N][11][2][2][11], b[N], am[N];
int st;

inline int nxt (int idx) {
	return ((idx + 1) % n);
}

inline int pre (int idx) {
	return ((idx - 1 + n) % n);
}

int m (int x) {
	if (x < MOD) return x;
	return x - MOD;
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
	cin >> n;
	for (int i = 0;i < n;i++) cin >> b[i];
	for (int i = 0;i < n;i++) am[i] = min(b[pre(i)], min(b[i], b[nxt(i)]));
	for (int i = 0;i <= am[0];i++) if (i < b[0]) dp[0][i][0][0][i] = 1; else dp[0][i][1][1][i] = 1;
	for (int x = 0;x <= am[0];x++) for (int st = 0;st <= 1;st++) for (int j = 0;j <= am[1];j++) {
		if (j < b[1] && x < b[1]) {
			if (j < b[0]) dp[1][j][0][st][x] += m(dp[0][x][0][st][x] + dp[0][x][1][st][x]), dp[1][j][0][st][x] = m(dp[1][j][0][st][x]);
			else dp[1][j][0][1][x] += m(dp[0][x][0][st][x] + dp[0][x][1][st][x]), dp[1][j][0][1][x] = m(dp[1][j][0][1][x]);
		}
		else {
			if (j < b[0]) dp[1][j][1][st][x] += m(dp[0][x][0][st][x] + dp[0][x][1][st][x]), dp[1][j][1][st][x] = m(dp[1][j][1][st][x]);
			else dp[1][j][1][1][x] += m(dp[0][x][0][st][x] + dp[0][x][1][st][x]), dp[1][j][1][1][x] = m(dp[1][j][1][1][x]);
		}
	}
	for (int i = 2;i < n;i++) {
		int p = i - 1;
		for (int x = 0;x <= am[0];x++) for (int st = 0;st <= 1;st++) {
			for (int j = 0;j <= am[i];j++) {
				for (int z = 0;z <= am[p];z++) {
					if (j < b[i] && z < b[i]) {
						if (j < b[p]) dp[i][j][0][st][x] += dp[p][z][1][st][x];else dp[i][j][0][st][x] += m(dp[p][z][0][st][x] + dp[p][z][1][st][x]);
						dp[i][j][0][st][x] = m(dp[i][j][0][st][x]);
					}
					else {
						if (j < b[p]) dp[i][j][1][st][x] += dp[p][z][1][st][x];
						else dp[i][j][1][st][x] += m(dp[p][z][0][st][x] + dp[p][z][1][st][x]);
						dp[i][j][1][st][x] = m(dp[i][j][1][st][x]);
					}
				}
			}
		}
	}
	int ans = 0;
	for (int x = 0;x <= am[0];x++) for (int i = 0;i <= am[n - 1];i++) {
		ans += dp[n - 1][i][1][1][x]; ans = m(ans);
		if (i >= b[0]) ans += dp[n - 1][i][1][0][x];
		if (x >= b[n - 1]) ans += dp[n - 1][i][0][1][x];
		ans = m(ans);
	}
	cout << ans << endl;
	return 0;
} 

标签:return,idx,..,int,题解,蓝桥,2022,ans,dp
From: https://www.cnblogs.com/zxh-mc/p/16988409.html

相关文章

  • CF939F Cutlet 题解
    题意简述有一个正反面都为\(0\)的卡片,每过\(1\)分朝下那一面的数值就会增加\(1\),你可以在几个区间的时间内翻转卡片,求经过\(2n\)秒后能否让这个卡片的正反面的数都......
  • 【阿里开发者】2018-2022年精选文章-后端篇
    2022年精选文章​​代码重构:面向单元测试​​​​从业务开发中学习和理解架构设计​​​​深度解读RocketMQ存储机制​​​​提升Java字符串编码解码性能的技巧​​​​解......
  • 【腾讯技术工程】2022年精选文章后端篇
    2022年精选文章​​一文搞懂Redis架构演化之路​​​​数据仓库开发SQL使用技巧总结​​​​深入理解Linux的TCP三次握手​​​​浅谈协程​​​​分布式唯一ID生......
  • let’s go——2022年读书活动招募书(第1期)
    作为一名编程人员,时常有一个想法,怎么精通某种技术?然后,业内大牛给你分享了一条学习路线,当你看完这条路线之后,之前高涨的心情瞬间低落下来,因为“万丈高楼平地起”,那条路的尽头......
  • k倍区间【第八届蓝桥杯省赛C++B组,第八届蓝桥杯省赛JAVAB组】
    k倍区间给定一个长度为\(N\)的数列,\(A1,A2,…AN\),如果其中一段连续的子序列\(Ai,Ai+1,…Aj\)之和是\(K\)的倍数,我们就称这个区间\([i,j]\)是\(K\)倍区间。你能......
  • 20220215_安装nvidia gpu
    20220215_安装nvidiagpu版本信息:centos8.5一、安装步骤:1.1.下载驱动,注意版本下载对应驱动https://www.nvidia.cn/Download/index.aspx?lang=cnlscpi//先查看硬件设备型号......
  • 记录2022年微服务技术架构选型
    后端技术栈套用互联网上的一句话,在java领域里面躲不过去的alibaba,所以本次微服务架构选型还是基于SpringCloudAlibaba做为基础。在SpringCloud众多的实现方案中,Sprin......
  • 牛客多校训练营2022年(一)
    LexicographicalMaximumEibwenisanewbieinPython.Youmightknowthatwhenyouinputanumberinthecommandline,yourPythonprogramwillreceiveastri......
  • YACS 11 月甲题解
    https://iai.sh.cn/contest这把还是简单的,难度对标普及组。所有题解均口胡。T1观察&性质你扫左端点,然后维护以当前左端点最长的合法子段,显然右端点单不降,因为当你......
  • 【LeetCode】题解合集(JavaScript版)
    前言:今年断断续续写了些LeetCode题目,一方面是为了一个比较现实的问题——面试,最重要的是要复习之前学习的数据结构与算法。后面有时间还会接续刷题…题解合集:题号题目题解1......