题目链接
题意:
给定长度为 n ( 2 ≤ n ≤ 1 0 6 ) (2≤n≤10^6) (2≤n≤106) 的仅包含字符'a'
,'b'
,'c'
的字符串,找到满足下列条件的最短字串,输出其长度。
- 长度至少为2;
- ‘a’出现的次数严格都大于’b’,'c’出现的次数。
思路:
仅包含三种字符,就使得只需要判断少量的情况,其他的情况可以划分为更小规模的问题。这是突破口。
如果一个字符串的长度为2,3,4,5,7时,需要判断其是否是满足条件的子串(可能满足);但是如果不是,那么其一定可以分解出长度为上述数字的子串是满足的。
比如:
长度为2:aa
,本身满足
长度为3:aca
,同上
长度为4:abca
,同上
长度为5:abbca
,同上
长度为6:abbcaa
,最后三个字符满足,长度为3,可以在搜索所有长度为3的子串时找到。
长度为7:abbacca
,本身满足
长度为8:abbaacca
,前五个字符满足,长度为5,可以在搜索所有长度为5的子串时找到。
长度为9:abbacacac
,第四到六个字符满足,长度为3,可以搜索在所有长度为3的子串时找到。
…
长度为 n … 其他长度的串都可以从中找出长度为2或3或4或5或7的满足子串。
所以,只需要判断长度为2,3,4,5,7的所有字串是否满足就可以了。
Code:
const int N = 1000010, mod = 1e9+7;
int T, n, m;
char a[N];
int cnta[N],cntb[N],cntc[N];
bool pd(int len)
{
for(int i=1;i<=n-len+1;i++)
{
int cnt1 = cnta[i+len-1]-cnta[i-1];
int cnt2 = cntb[i+len-1]-cntb[i-1];
int cnt3 = cntc[i+len-1]-cntc[i-1];
if(cnt1>cnt2&&cnt1>cnt3) return 1;
}
return 0;
}
int main(){
Ios;
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
cnta[i]=cnta[i-1];
cntb[i]=cntb[i-1];
cntc[i]=cntc[i-1];
if(a[i]=='a') cnta[i]++;
else if(a[i]=='b') cntb[i]++;
else cntc[i]++;
}
if(pd(2)) cout<<2<<"\n";
else if(pd(3)) cout<<3<<"\n";
else if(pd(4)) cout<<4<<"\n";
else if(pd(5)) cout<<5<<"\n";
else if(pd(7)) cout<<7<<"\n";
else cout<<-1<<"\n";
}
return 0;
}
经验:
看到字符种类较少时,应该想到,较长的长度的串中 可能有 较短长度的子串 所具有的性质。