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;
}
相关推荐
我爱工作&工作love我6 分钟前
P4913 【深基16.例3】二叉树深度 dfs-二叉树的遍历
算法·深度优先·图论
TracyCoder12313 分钟前
LeetCode Hot100(25/100)——2. 两数相加(链表)
算法·leetcode·链表
long31614 分钟前
Z算法(线性时间模式搜索算法)
java·数据结构·spring boot·后端·算法·排序算法
望未来无悔25 分钟前
系统学习算法 专题十九 优先级队列(堆)
java·算法
啊阿狸不会拉杆25 分钟前
《机器学习导论》第3章 -贝叶斯决策理论
人工智能·python·算法·机器学习·numpy·深度优先·贝叶斯决策理论
阿蔹26 分钟前
力扣面试题二Python
python·算法·leetcode·职场和发展
永远睡不够的入28 分钟前
类和对象(下):流重载、初始化列表、友元
c++
Trouvaille ~38 分钟前
【Linux】UDP Socket编程实战(四):地址转换函数深度解析
linux·服务器·网络·c++·udp·socket·地址转换函数
王老师青少年编程40 分钟前
2022信奥赛C++提高组csp-s复赛真题及题解:星战
c++·真题·csp·信奥赛·csp-s·提高组·星战
jaysee-sjc42 分钟前
【项目二】用GUI编程实现石头迷阵游戏
java·开发语言·算法·游戏