牛客网 wannafly挑战赛 28 B msc和mcc

链接: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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值