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;
}
相关推荐
普通网友12 分钟前
内存对齐与缓存友好设计
开发语言·c++·算法
小白程序员成长日记14 分钟前
2025.11.18 力扣每日一题
算法·leetcode·职场和发展
Cathyqiii27 分钟前
传统扩散模型 VS Diffusion-TS
人工智能·算法
海边夕阳200631 分钟前
【每天一个AI小知识】:什么是逻辑回归?
人工智能·算法·逻辑回归
普通网友36 分钟前
C++编译期数据结构
开发语言·c++·算法
Gorgous—l36 分钟前
数据结构算法学习:LeetCode热题100-图论篇(岛屿数量、腐烂的橘子、课程表、实现 Trie (前缀树))
数据结构·学习·算法
代码程序猿RIP43 分钟前
【C++开发面经】全过程面试问题详解
java·c++·面试
im_AMBER44 分钟前
算法笔记 13 BFS | 图
笔记·学习·算法·广度优先
普通网友1 小时前
嵌入式C++安全编码
开发语言·c++·算法
云知谷1 小时前
【软件测试】《集成测试全攻略:Mock/Stub 原理 + Postman/JUnit/TestNG 实战》
c语言·开发语言·c++·软件工程·团队开发