1. 程式人生 > >Wannafly挑戰賽28: B. msc和mcc(思維)

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’。

輸出描述:

一行一個正整數,表示答案。

輸入

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;
}