题意;给你一堆字符串,仅包含字符ASD,求出所有拼接方案中子串‘SAD’的最多出现次数。
很明显我们只需要考虑串与串相接的部分所带来的贡献最大值。
第一次分类:S+AD,SA+D。
意思是说,串后缀为S配前缀为AD,后缀为AD配前缀为D。
那我们按照串前缀普通,为S,为SA。
后缀普通,为D,为SD分类,再排列组合,共九种可能。
单独一个字母A提出来单独讨论。
因为前缀为D的不可能为SD,后缀为S的不可能是SA,也就是没有交集。
所以我们一定可以用某种方式将它们排好,让每一个都发挥用处。
除非:以S+AD为例。
1.如果S和AD的数量一样多,而且恰好分布在同样的串上,也就是全都长成SxxxxAD这样。
很明显最开头和最结尾的不能相连,方案减一。
2.不算单独的A,不算没有特殊前后缀的串,假设剩下的串有x个,那最多产生x-1个相交SAD。如果算出来是x个,那自然要减一。
对于单独的A。
A的作用就是弥补S,AD,SA,D数量不均有剩余的情况。
A可以将一个S修改成SA。所以我们可以枚举用多少个A去插进去。代码就很好理解了。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
int t;
int n;
char ch[233];
int num[10],pre[5],suf[5];
int sum=0,cnta;
signed main(){
t=in;
while(t--){
n=in;sum=cnta=0;
memset(num,0,sizeof(num));memset(pre,0,sizeof(pre));memset(suf,0,sizeof(suf));
for(int i=1;i<=n;i++){
scanf("%s",ch+1);int len=strlen(ch+1);
if(len==1&&ch[1]=='A'){
cnta++;continue;
}
int idp=0,ids=0;
if(ch[1]=='D')ids=1;
if(len>1&&ch[1]=='A'&&ch[2]=='D')ids=2;
if(ch[len]=='S')idp=1;
if(ch[len-1]=='S'&&ch[len]=='A')idp=2;
num[idp*3+ids]++;
pre[idp]++;suf[ids]++;
if(len>2){
for(int j=1;j<=len-2;j++){
if(ch[j]=='S'&&ch[j+1]=='A'&&ch[j+2]=='D')
sum++;
}
}
}
int other=0;
for(int i=1;i<=2;i++){
int tmp=min(pre[i],suf[3-i]);
if(tmp>0&&pre[i]==suf[3-i]&&suf[3-i]==num[i*3+3-i])
tmp--;
other+=tmp;
}
for(int i=1;i<=cnta;i++){
if(i>pre[1])break;
int tmp=min(pre[1]-i,suf[2])+min(pre[2]+i,suf[1]);
other=max(other,tmp);
}
if(other>0&&other==n-num[0]-cnta)other--;
printf("%d\n",other+sum);
}
return 0;
}