题意
给出一个后缀数组,以及每个位置上填某个字母的价值,求出最大的价值总和。
思路
根据后缀数组的性质,我们可以设fi,jf_{i,j}fi,j为第AiA_iAi个位置上填字母jjj的最大价值。
得出动态转移方程:
fi,j=max(fi,j,fi−1,k+wAi,j){k<j}f_{i,j}=max(f{i,j},f{i-1,k}+w_{A_{i,j}})\{k<j\}fi,j=max(fi,j,fi−1,k+wAi,j){k<j}
fi,j=max(fi,j,fi−1,k+wAi,j){k=j,rank[A[i]+1]<=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] <= rank[A[i - 1] + 1]\}fi,j=max(fi,j,fi−1,k+wAi,j){k=j,rank[A[i]+1]<=rank[A[i−1]+1]}
其中rankirank_iranki表示从iii的后缀的排名,根据后缀数组按字典序的排名,我们可以知道sAi≤sAi+1s_{A_i}\leq s_{A_i+1}sAi≤sAi+1,其中$sAi=sAi+1s_{A_i}= s_{A_i+1}sAi=sAi+1的情况时,AiA_iAi的后缀字典序排名是<Ai+1<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);
}