第二道不想改,第三道不會,第一道先放這吧;
何大爺對字符串十分有研究,於是天天出字符串題虐殺 zhx。 何大爺今天爲
字符串定義了新的權值計算方法。一個字符串由小寫字母組成,字符串的權值
被定義爲其中出現次數最多的字符的次數減去出現次數最少的字符的次數。(注
意,在討論出現最少的字符的時候,該字符必須至少出現一次)現在何大爺給
你一個字符串,何大爺想知道這個字符串的所有子串中權值最大的權值是多
少?
【輸入格式】
第一行一個整數n,代表字符串的長度。
接下來一行n個小寫字母,代表該字符串。
【輸出格式】
一行一個整數代表答案。
【樣例輸入】
10
aabbaaabab
【樣例輸出】
3
【數據範圍與規定】
對於30%的數據, 1 ≤ n≤ 100。
對於60%的數據, 1 ≤ n ≤ 1000。
對於100%的數據, 1 ≤ n ≤ 10^6.
顯然需要O(n)的做法;
考場上的我用的尺取法,移動條件是ans值是否被更新;
顯然這樣只考慮了局部最優,卻並不是全局最優,很容易就可以找到反例;
正解是動態規劃?
mins[i][j] : 當前字符i與j出現次數的最小差值;
pos[i][j]:最小差值的位置;
sum[i]:當前字符i出現的次數;
pre[i]:當前字符i最後出現的位置;
思想挺巧妙的,反正我是想不到<-_<-;
感謝summer學姐的精彩講解qwq;
總結:
1.考場上想不出正解就打暴力,不要對自己的正解過於自信,除非可以完美地證明其正確性;垃圾cgold,考試倒數,怎麼還不滾粗
2.分段暴力;
3.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=30;
int mins[MAXN][MAXN],pos[MAXN][MAXN],sum[MAXN],pre[MAXN];
int n,ans;
char s[1000002];
void solve()
{
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++)
{
int c=s[i]-'a'+1;
sum[c]++,pre[c]=i;
for(int j=1;j<=26;j++)
{
int cnt1=0,cnt2=0;
if(j==c || !sum[j]) continue;
if(pre[j]==pos[c][j]) cnt1++;//題目中明確說,要求字符j至少出現一次,如果j最後出現的位置爲pos,我們減去後,j出現的次數就變成了0,所以需要把j至少算上一次,即差值需要減1;
if(pre[j]==pos[j][c]) cnt2++;
ans=max(ans,max(sum[c]-sum[j]-cnt1-mins[c][j],sum[j]-sum[c]-cnt2-mins[j][c]));
}
for(int j=1;j<=26;j++)
{
if(sum[c]-sum[j]<mins[c][j]) //更新mins
mins[c][j]=sum[c]-sum[j],pos[c][j]=i;
if(sum[j]-sum[c]<mins[j][c])
mins[j][c]=sum[j]-sum[c],pos[j][c]=i;
}
}
cout<<ans;
return;
}
int main()
{
solve();
return 0;
}