链接:https://ac.nowcoder.com/acm/contest/217/B
来源:牛客网
题目描述
msc和mcc是一对好朋友,有一天他们得到了一个长度为n的字符串s.
这个字符串s十分妙,其中只有’m’,’s’和’c’三种字符。
定义s[i,j]表示s中从第i个到第j个字符按顺序拼接起来得到的字符串。
定义一个字符串t的子序列为从t中选出一些位置并且将这些位置上面的字符按顺序拼接起来得到的字符串。
两个子序列重合当且仅当存在一个位置x使得两个子序列同时选择了位置x。
由于msc和mcc是一对很好很好的好朋友,所以她们希望选择两个数字x和y满足1≤x≤y≤n使得s[x,y]中同时存在两个**不重合的子序列**使得其中一个是’msc’且另外一个是’mcc’
现在给出n和字符串s,问她们可以选出多少对不同的(x,y)。
输入描述:
第一行一个正整数n,表示字符串s的长度。 第二行一个长度为n的字符串s,其中s只包含字符’m’,’s’和,’c’。
输出描述:
一行一个正整数,表示答案。
输入
6 mscmcc
输出
1
对于长度为6的字符串,如果能找到两个不重叠的子序列,满足一个是"msc",一个是"mcc",只有8种情况:
①mccmsc;②mcmcsc;③mcmscc;④mmccsc
⑤mmcscc;⑥mmsccc;⑦mscmcc;⑧msmccc
这样问题可以转化成:有多少对(x, y)满足在区间[x, y]内存在上述8种子序列其中之一
暴力枚举x,对于每个x找到满足条件最小的y,那么答案是就∑(n-y+1)
主要是怎么找到最小的y:
可以预处理next[x][y]表示对于位置x往后,下一个字符y在哪里(y∈{'m', 'c', 's'})
这样的话对于上面每种情况,只需要跳6次就可以确定y了(当然可能y不存在,这个时候贡献为0)
然后有8种情况,所以整体复杂度O(8*6*n)
代码非常短
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
char str[100005], temp[11][11] = {"kmccmsc", "kmcmcsc", "kmcmscc", "kmmccsc", "kmmcscc", "kmmsccc", "kmscmcc", "kmsmccc"};
int net[100005][28];
int main(void)
{
LL ans = 0;
int n, i, p, j, now, bet;
scanf("%d%s", &n, str+1);
for(i='a';i<='z';i++)
{
for(j=n;j>=1;j--)
{
net[j-1][i-'a'] = net[j][i-'a'];
if(str[j]==(char)i)
net[j-1][i-'a'] = j;
}
}
for(i=1;i<=n;i++)
{
bet = n+1;
for(p=0;p<=7;p++)
{
now = i-1;
for(j=1;j<=6;j++)
{
now = net[now][temp[p][j]-'a'];
if(now==0)
break;
}
if(now!=0)
bet = min(bet, now);
}
ans += n-bet+1;
}
printf("%lld\n", ans);
return 0;
}