链接: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’。
输出描述:
一行一个正整数,表示答案。
示例1
输入
复制
6 mscmcc
输出
复制
1
暴力每个x,求出最小的满足条件的位置z,求一遍和。问题是如何求出这个位置。
满足条件的序列很少,实际上只有八中:
mccmsc
mcmcsc
mcmscc
mmccsc
mmcscc
mmsccc
mscmcc
msmccc
问题转化为从i起找到可以满足以上子序列的最靠前的位置,可以记录一个next[i][j],表示第i个位置后下一个字母为j的最靠前位置。不过我写的是二分暴力位置。
#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
const int maxm = 100005;
const int INF = 1e9 + 7;
char ch[9][10], str[maxm];
int m[maxm], s[maxm], c[maxm];
int work(int len, int *p, int x)
{
int l = 1, r = len, ans = 0;
while (l <= r)
{
int mid = (l + r) / 2;
if (p[mid] > x)
ans = p[mid], r = mid - 1;
else l = mid + 1;
}
return ans;
}
int main(void)
{
int n, L, id, i, j, k, sm, ss, sc;
ll ans = 0;
sm = ss = sc = 0;
strcpy(ch[1] + 1, "mccmsc");
strcpy(ch[2] + 1, "mcmcsc");
strcpy(ch[3] + 1, "mcmscc");
strcpy(ch[4] + 1, "mmccsc");
strcpy(ch[5] + 1, "mmcscc");
strcpy(ch[6] + 1, "mmsccc");
strcpy(ch[7] + 1, "mscmcc");
strcpy(ch[8] + 1, "msmccc");
scanf("%d", &n);
scanf("%s", str + 1);
for (i = 1;i <= n;i++)
{
if (str[i] == 'm') m[++sm] = i;
else if (str[i] == 's') s[++ss] = i;
else c[++sc] = i;
}
ans = 0;
for (i = 1;i <= n;i++)
{
id = INF;
for (j = 1;j <= 8;j++)
{
int now = i - 1, tmp = 1;
while (tmp <= 6)
{
if (ch[j][tmp] == 'm')
now = work(sm, m, now);
else if (ch[j][tmp] == 's')
now = work(ss, s, now);
else now = work(sc, c, now);
if (now == 0) break;
tmp++;
}
if (tmp <= 6) continue;
id = min(id, now);
}
if (id != INF)
ans += n - id + 1;
}
printf("%lld\n", ans);
return 0;
}