2023牛客暑期多校-J-Qu‘est-ce Que C‘est?(DP)

题意:

给定长度为n的数列,要求每个数都在的范围,且任意长度大于等于2的区间和都大于等于0,问方案数。

思路:

首先要看出是dp题,用来表示遍历到第i位且后缀和最小为x 的可行方案数(此时的后缀可以只有最后一位)。很显然j的值在区间。下面考虑dp如何转换:

1.对于。 先讨论可由加一位值为 转换而来;也可由加一位值为0 转换而来。就有。再讨论,可由,加一位值为 转换而来;也可由 加一位值为1转换而来。就有。依次讨论可以得出可以由,末位加值为转换而来;也可由,末位加x转换而来。综上所诉:

2.对于。可以去验证,只有,末位加值为x 才能转换成。所以

为了方便计算我们把这个区间平移映射到区间上。按照上述思想去找新的dp转换式就有:

由于都是求和到2m,所以可以考虑后缀和优化。

代码:

复制代码
//#define _CRT_SECURE_NO_WARNINGS 
//#include<iostream>
//#include<algorithm>
//#include<cstdio>
//#include<map>
//#include<string.h>
//#include<string>
//#include<vector>
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 998244353;
const int N = 5005;
ll dp[N][N*2];//dp[i][j]表示遍历到i位,后缀和最小为j且合法的数量。(这里后缀和包含了只含有最后一位的情况)
ll sum[N * 2];//后缀数组
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m;
	ll ans = 0;
	//初始化
	for (int i = 0; i <= m*2; i++)
	{
		dp[1][i] = 1;
	}
	for (int i = 2; i <= n; i++)
	{
		//处理后缀和
		for (int j = m * 2; j >= 0; j--)sum[j] = (sum[j + 1] + dp[i - 1][j]) % mod;
		//[0,m)的情况
		for (int j = 0; j < m; j++)
		{
			dp[i][j] = sum[2 * m - j];
		}
		//[m,2m]的情况
		for (int j = m; j <= 2 * m; j++)
		{
			dp[i][j] = sum[j - m];
		}
	}
	//统计
	for (int i = 0; i <= m * 2; i++)
	{
		ans = (ans + dp[n][i]) % mod;
	}
	cout << ans << endl;
	return 0;
}
相关推荐
橙几19 分钟前
击败了90%的解法?Two Sum 从 O(n²) 到 O(n) 的优化之路
算法
叶子爱分享33 分钟前
经典排序算法之归并排序(Merge Sort)
算法·排序算法
珹洺39 分钟前
C++算法竞赛篇:DevC++ 如何进行debug调试
java·c++·算法
呆呆的小鳄鱼1 小时前
leetcode:冗余连接 II[并查集检查环][节点入度]
算法·leetcode·职场和发展
墨染点香1 小时前
LeetCode Hot100【6. Z 字形变换】
java·算法·leetcode
沧澜sincerely1 小时前
排序【各种题型+对应LeetCode习题练习】
算法·leetcode·排序算法
CQ_07121 小时前
自学力扣:最长连续序列
数据结构·算法·leetcode
弥彦_2 小时前
cf1925B&C
数据结构·算法
YuTaoShao2 小时前
【LeetCode 热题 100】994. 腐烂的橘子——BFS
java·linux·算法·leetcode·宽度优先
古月-一个C++方向的小白7 小时前
C++11之lambda表达式与包装器
开发语言·c++