题目
大意
把一个字符串的所有非空后缀按字典序从小到大排序,然后按顺序排列出后缀的第一个字符在原串中的位置所形成的数组,就是后缀数组。如“ababa”的后缀数组就是{5, 3, 1, 4, 2}。
给定一个长度为n的数组A,以及一个n × 26 的矩阵w,所有下标都从1开始,其中w_{i, j}表示第i个位置填第j个小写字母的价值,现在你需要给出一个长度为n的字符串,使得它的后缀数组是A,而且它每个位置的价值和最大。
分析
每个字母对应后缀数组的一段区间
考虑一下后缀数组中每个下标的后继在后缀数组中的位置,形成一个新的数组,那么每个字母对应的区间中这个数组的元素一定是单调递增的
然后直接设f[i][j]表示到了后缀数组中的第i个位置,填到了第j个字母的最大价值
n==1 特别处理一下
代码
1 #include<iostream>
2 #define N 100010
3 using namespace std;
4 int n,seed,w[N][30],a[N],z[N],rank[N],f[N][30],ans;
5 int rand()
6 {
7 seed=(long long)(100000005ll*(long long)seed+1532777326ll)%998244353ll;
8 return seed/100;
9 }
10 int main ()
11 {
12 ios::sync_with_stdio(false);
13 cin>>n>>seed;
14 for (int i=1;i<=n;i++)
15 for (int j=0;j<26;j++)
16 w[i][j]=rand()%10000;
17 for (int i=1;i<=n;i++)
18 cin>>a[i],rank[a[i]]=i;
19 for (int i=0;i<26;i++)
20 {
21 f[1][i]=w[a[1]][i];
22 if (n==1) ans=max(ans,f[1][i]);
23 }
24 for (int i=2;i<=n;i++)
25 {
26 for (int j=0;j<26;j++)
27 {
28 for (int k=0;k<=j;k++)
29 {
30 if (k==j&&rank[a[i]+1]<=rank[a[i-1]+1]) continue;
31 f[i][j]=max(f[i][j],f[i-1][k]+w[a[i]][j]);
32 }
33 if(i==n) ans=max(ans,f[i][j]);
34 }
35 }
36 cout<<ans;
37 }