第十六届东北地区大学生程序设计竞赛(热身赛)B-String Value(字符串dp)

TP

题意:

  • 给定一个字符串,求这个字符串所有 连续子串 中,出现最多的字符次数减去出现最少的字符个数 的值 最大是多少。

思路:

  • dp,字符串类型,尝试与 26 个字母联系
  • ∣ s ∣ ≤ 1 0 6 ∣s∣≤10^6 s106 ,要注意内存限制。

两种代码,细节注释。

C o d e : Code: Code:

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define all(a) a.begin(),a.end()
#define sz(a) (int)a.size()
#define oper(a) operator<(const a& ee)const
#define endl '\n'
#define ul (u << 1)
#define ur (u << 1 | 1)
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e8;
int INF = 0x3f3f3f3f; ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
int dp[2][26][26];
//只看后两位的话,dp[j][k] 代表 前 i 位形成的所有连续子串中,
//j 字符出现最多,k 字符出现最少的情况的最大差

//只看第一位,dp[0] 收集的是 j、k 字符有可能不存在的情况,
//dp[1] 收集的情况,j、k 字符都必须存在,这样最大差才合法
char s[N];

void solve() {
    cin >> s + 1;
    n = strlen(s + 1);

    int ans = 0;
    mem(dp[1], -0x3f);//初始字符都不存在,不合法

    for (int i = 1; i <= n; i++) {
        int u = s[i] - 'a';
        //当前字符是什么,对应影响部分状态

        for (int j = 0; j < 26; j++) {
            if (u == j)continue;//相同没有意义
            //当前出现 u ,u、j 状态最大差++

            dp[0][u][j]++;
            dp[1][u][j]++;
            ans = max(ans, dp[1][u][j]);//随时维护最优解
        }

        for (int j = 0; j < 26; j++) {
            if (u == j)continue;
            //当前出现 u ,j、u 状态最大差--

            dp[1][j][u]--;
            dp[1][j][u] = max(dp[1][j][u], dp[0][j][u] - 1);
            //一旦出现过一次 u,之后累计的 j、u 状态才有可能合法
            //由 dp[0] 赋给 dp[1]

            dp[0][j][u] = max(dp[0][j][u] - 1, 0);
            // dp[0] 不需要维护负数
        }
    }

    cout << ans;
}

int main() {
    cinios;
    int T = 1;
    for (int t = 1; t <= T; t++)
        solve();
    return 0;
}
/*
*/

C o d e : Code: Code:

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define all(a) a.begin(),a.end()
#define sz(a) (int)a.size()
#define oper(a) operator<(const a& ee)const
#define endl "\n"
#define ul (u << 1)
#define ur (u << 1 | 1)
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e6 + 10, M = 1e6 + 10, mod = 1e9 + 7;
int INF = 0x3f3f3f3f; ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
struct node
{
    int w, f1, f2;
}dp[26][26];
char s[N];

void solve() {
    cin >> s + 1;
    n = strlen(s + 1);

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        int u = s[i] - 'a';

        for (int j = 0; j < 26; j++) {
            if (u == j)continue;

            dp[u][j].w++;
            if (dp[u][j].f1)ans = max(ans, dp[u][j].w);
            //f1 标记 j 字符是否存在,不存在不能计入答案

            dp[j][u].w = max(dp[j][u].w - 1, -1);
            //最短也要是 -1,即只有一个 u 字符作为开头的情况,再短可舍去

            dp[j][u].f1 = 1;//u 字符存在

            if (dp[j][u].w == -1)dp[j][u].f2 = 1;//如果 u 字符开头就标记
            else if (dp[j][u].f2) {

                //在之后再次遇到 u 字符时,显然开头那个 u 可以舍去,也不影响 u 字符的存在性

                dp[j][u].w++;//长度++
                dp[j][u].f2 = 0;
            }
        }
    }

    cout << ans;
}

int main() {
    cinios;
    int T = 1;
    for (int t = 1; t <= T; t++)
        solve();
    return 0;
}
/*
*/
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值