当前位置: 代码迷 >> 综合 >> NOIP2018 模拟测试 day2 作诗2
  详细解决方案

NOIP2018 模拟测试 day2 作诗2

热度:16   发布时间:2023-12-06 07:59:06.0

题目:
作诗2

描述
SHY是T国的公主,平时的一大爱好是作诗。不过这次赶潮流的SHY作了一首英文诗。
英文诗的长度为N,用一个仅含有26个小写拉丁字母的字符串表示。
SHY把这首诗拿给LYD欣赏,LYD突发奇想,想从这首诗中找出一段,
使得这一段中出现最多的字母出现的次数与出现最少的字母出现的次数的差值最大。
现在请你求出这个最大差值吧。输入格式
第一行是一个整数N;
第二行是一个长度为N的字符串,字符串中只含有26个小写拉丁字母。输出格式
输出一个整数表示最大差值。样例输入
10
aabbaaabab
样例输出
3
数据范围与约定
对于40%的数据: N≤5000
对于100%的数据: N≤1000000,保证字符串中至少出现两种字母。
要注意的是,“出现次数最少的字母”的出现次数不能为0,也就是在选取的那一段中它必须存在。
样例解释
选取aaaba这一段,最大差值为3

思路:
dp。
设当前枚举到了第i位。
a[x]表示x字符的个数。
f[x][y]表示最大个数的字符为x,最小个数的字符为y的差值。
转移 f[x][y]=max(a[x]-a[y]),ans=max(a[y]-a[j]+f[j][y],a[j]-a[y]+f[y][j])

代码:

#include<bits/stdc++.h>
using namespace std;#define maxn 1000000
#define read(x) scanf("%d",&x);int n;
int a[maxn+5];
int f[maxn+5][30];
int g[maxn+5][30];int main() {
    read(n);int ans=0;for(int i=1;i<=26;i++) {
    for(int j=1;j<=26;j++) {
    f[i][j]=(1<<31);}}for(int i=1;i<=n;i++) {
    char x;while((~scanf("%c",&x))&&(!isalpha(x)));int y=x-'a'+1;a[y]++;for(int j=1;j<=26;j++) {
    if(y==j) continue;f[y][j]=max(f[y][j],g[y][j]);g[y][j]=a[y]-a[j];ans=max(ans,max(a[y]-a[j]+f[j][y],a[j]-a[y]+f[y][j]));}}printf("%d",ans);return 0;
}