【动态规划 字符串】JZOJ_4227 B

本文介绍了一种利用后缀数组求解最大价值填字问题的算法。通过动态规划和后缀数组的特性,计算出在每个位置填入特定字母所能获得的最大价值总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

给出一个后缀数组,以及每个位置上填某个字母的价值,求出最大的价值总和。

思路

根据后缀数组的性质,我们可以设fi,jf_{i,j}fi,j为第AiA_iAi个位置上填字母jjj的最大价值。
得出动态转移方程:
fi,j=max(fi,j,fi−1,k+wAi,j){k&lt;j}f_{i,j}=max(f{i,j},f{i-1,k}+w_{A_{i,j}})\{k&lt;j\}fi,j=max(fi,j,fi1,k+wAi,j){k<j}
fi,j=max(fi,j,fi−1,k+wAi,j){k=j,rank[A[i]+1]&lt;=rank[A[i−1]+1]}f_{i,j}=max(f{i,j},f{i-1,k}+w_{A_{i,j}})\{k=j,rank[A[i] + 1] &lt;= rank[A[i - 1] + 1]\}fi,j=max(fi,j,fi1,k+wAi,j){k=jrank[A[i]+1]<=rank[A[i1]+1]}
其中rankirank_iranki表示从iii的后缀的排名,根据后缀数组按字典序的排名,我们可以知道sAi≤sAi+1s_{A_i}\leq s_{A_i+1}sAisAi+1,其中$sAi=sAi+1s_{A_i}= s_{A_i+1}sAi=sAi+1的情况时,AiA_iAi的后缀字典序排名是&lt;Ai+1&lt;A_{i+1}<Ai+1的,由于第一个字母相同,我们加111比较剩下的字典序。

代码

#include<cstdio>
#include<algorithm>

int n, ans;
long long x;
int A[100001], rank[100001], w[100001][27], f[100001][27];

int ranint() {
	x = (100000005 * x + 1532777326) % 998244353;
	return x / 100;
}

int main() {
	scanf("%d %d", &n, &x);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &A[i]);
		rank[A[i]] = i;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= 26; j++)
			w[i][j] = ranint() % 10000;
	for (int i = 1; i <= 26; i++)
		f[1][i] = w[A[1]][i];
	for (int i = 2; i <= n; i++)
		for (int j = 1; j <= 26; j++)
			for (int k = 1; k <= j; k++) {
				if (k == j && rank[A[i] + 1] <= rank[A[i - 1] + 1]) continue;
				f[i][j] = std::max(f[i][j], f[i - 1][k] + w[A[i]][j]);
			}
	for (int i = 1; i <= 26; i++)
		ans = std::max(ans, f[n][i]);
	printf("%d", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值