JZ Day11 T3 B

题目大意:

小D是雅礼高一著名的神犇,在NOI同步赛中获得了满分的优异成绩,而全国没有任何其他人获得如此的成绩。
某天晚上,高一内部在讨论一道题目,然而包括小D之内的各种神犇都毫无头绪,这时候,高二的人赢小T上来给高二进行了精彩的讲解。
小D被小T的神犇气场所折服,他知道小T之所以没有同步赛满分是不屑于,于是他决定拜小T为师。
一日小T正在给小D讲解后缀数组。
“把一个字符串的所有非空后缀按字典序从小到大排序,然后按顺序排列出后缀的第一个字符在原串中的位置所形成的数组,就是后缀数组。如“ababa”的后缀数组就是{5, 3, 1, 4, 2}。”
这里的位置从1开始编号,字符串仅包含小写英文字母。
接着小T给小D讲解了它的构造过程。
小D毕竟身为同步赛满分,水平还是不低,他立即举一反三:既然我们能给定一个字符串,给出他的后缀数组,那么给定后缀数组,能不能恢复字符串呢。
小T说:“这是不行的,这个问题我几年前研究过,譬如说,假设你后缀数组是{2, 1},那么原串既可以是“aa”,也可以是“ bb”。然而,我们的确可以提出一些有趣的问题,我记得我小学的时候,研究过一个问题,给定一个长度为n的数组A,以及一个n × 26 的矩阵w,所有下标都从1开始,其中w_{i, j}表示第i个位置填第j个小写字母的价值,现在你需要给出一个长度为n的字符串,使得它的后缀数组是A,而且它每个位置的价值和最大。这个问题可不简单,我小学的时候研究了整整一节课。”
小D想了想,觉得自己大概就算在小学也只要一节课就想得出来。各位做题人你们会做吗?


解题思路:

吐槽一波小D和小T都是变态吗?
d p dp
f i , j f_{i,j} 表示在原串中位于位置 i i ,所填字母为 j j 的最大价值和,那么 f i , j = f i 1 , k + w a i , j f_{i,j}=f_{i-1,k}+w_{a_i,j}
特判:举个例子 a b a b a ababa 是可以用相同的字母,那应该怎么办呢,那么 r a n k a i + 1 > = r a n k a i 1 + 1 rank_{a_i+1}>=rank_{a_{i−1}+1} 才可以保证合法,为什么呢, s i = s i 1 s_i=s_{i-1} ,那么只要往后移一位比较就可以了


A c c e p t e d   c o d e : Accepted\ code:

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)

using namespace std;

const int N = 1e5 + 5;

int n, ans, flag;
long long x; 
int a[N], b[N], z[N], w[N][30], f[N][30], Rank[N];

inline signed read() {
	int f = 0, flag = 1; char c = getchar();
	while (isdigit(c) == 0) flag = (c == '-') ? -1 : 1, c = getchar();
	while (isdigit(c) != 0) f = (f<<1) + (f<<3) + c - 48, c = getchar();
	return flag * f;
}

int main() {
	n = read(), x = read();
	for (int i = 1; i <= n; ++i) {
		Rank[(a[i] = read())] = i;
		for (int j = 1; j <= 26; ++j) {
			x = ((100000005ll * x + 1532777326ll) % 998244353ll);
			int r = floor(x / 100.0);
			w[i][j] = r % 10000;
		}
	}//题目要求的随机数据
	for (int i = 1; i <= 26; ++i) {
	  f[1][i] = w[a[1]][i];
	  if (n == 1) ans = max(ans, f[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] = max(f[i][j], f[i-1][k] + w[a[i]][j]);
			 }
			if (i == n) ans = max(ans, f[i][j]);
		}
	printf("%d\n", ans);
}

猜你喜欢

转载自blog.csdn.net/qq_39798042/article/details/86708732
今日推荐