1. 程式人生 > 其它 >字串極值題解

字串極值題解

題目連結

題目分析

現將字串轉化為數列,對於一個序列:

在列舉序列時,記 \(i\) 為當前數的下標。

可以記錄 \(now\) 值為最大的 \([k,i]\) 中序列和的值 \((1\leq k \leq i)\)\(ans\) 為最終的答案。

令初始 \(now=0\),每讀入一個新數 \(x\)

  • 如果 \(x>0\)\(now+=x\)\(ans=\max(ans,now)\)
  • 如果 \(x<0\),且 \(now+x>0\)\(now+=x\)
  • 如果 \(x<0\),且 \(now+x \leq 0\),直接令 \(now=0\)

上面這個過程不能解決序列全是負數的情況,如果出現序列中全是負數的情況,特判即可:

因為序列中沒有數值為 \(0\) 的數,所以在任意時刻,如果 \(now=0\),則目前序列中的數都為負數。只需要根據這一特性特判即可。

參考程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

int change(char ch) //將字母轉換為對應的值
{
    int ans;
    if ('a' <= ch && ch <= 'z')
        ans = -(ch - 'a' + 1);
    else
        ans = (ch - 'A' + 1);
    return ans;
}

ll T, n, maxn, now, len;
string str;
int main()
{
    cin >> T;
    while (T--) //多組資料
    {
        cin >> str;
        len = str.size();   //求串的長度
        now = change(str[0]); //掃描第一個數,賦值給 now

        maxn = now; //此時更新答案
        if (now < 0)    //如果 now 為負數,直接捨棄前面
            now = 0;   

        for (int i = 1; i < len; ++i)   //字串下標從0開始
        {
            ll x = change(str[i]);  //數

            if (x > 0)  //正數
            {
                now += x;
                maxn = max(now, maxn);
            }
            else    //負數
            {
                if (now + x < 0)    //加上 x 之後使得 now<0
                {
                    if (now == 0)   //特判全是負數的情況
                        maxn = max(x, maxn);
                    else   
                        now = 0;
                }
                else    //加上 x 之後 now>0
                    now += x;
                    // 因為 x 是負數,所以沒必要更新ans
            }
        }
        printf("%lld\n", maxn);
    }
    return 0;
}