1. 程式人生 > >5893. 【NOIP2018模擬10.4】括號序列

5893. 【NOIP2018模擬10.4】括號序列

Description

Input

Output

Sample Input

輸入1:
aabaab
輸入2:
abcabcabc
輸入3:
aabbcc

Sample Output

輸出1:
4
輸出2:
0
輸出3:
6

Data Constraint

solution    

用棧儲存字母 ,只要出現相同的字母就把兩個字母都退棧,並累計方案數。

考慮列舉起點,用棧跑一次,複雜度為O(n^{2})。

考慮優化。如果對於一個字首 1——>i,和另一個字首1——>j的棧相同,代表i+1——>j 的區間是一個合法區間, 因為i+1——>j 的字元都互相消完了,證明這是一個合法的區間。可以用hash記錄當前每一個字串出現的次數,然後累計答案。也可以用trie代替hash,這樣相比hash時間複雜度會大大減小。

code

1.hash版

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define N 1000000+200
long long st[N],d[N],pr[N],tmp[N];
long long tot,hash,ans,tw;
const long long p=19260817;
const long long mod=274876858367ll;
map <long long,long long> Hash;
int main()
{
	freopen("bracket.in","r",stdin);
	freopen("bracket.out","w",stdout);
	long long c;
	st[0] = 0;
	pr[0] = 1;
	for (c = getchar(); ('a' <= c) && (c <= 'z'); c = getchar())
	{
		st[++st[0]]=c-'a'+1;
		pr[st[0]]=pr[st[0]-1]*p%mod;
	}
	long long j=0;
	Hash[0]++;
	for(int i=1;i<=st[0];i++)
	{
		tmp[++tmp[0]]=st[i];
		j=(j+tmp[tmp[0]]*pr[tmp[0]])%mod;
		if(tmp[0]>1&&tmp[tmp[0]]==tmp[tmp[0]-1])
		{
			j=(j-tmp[tmp[0]]*pr[tmp[0]]%mod+mod-tmp[tmp[0]-1]*pr[tmp[0]-1]%mod+mod)%mod;
			tmp[0]-=2;
		}
		ans+=Hash[j];
		Hash[j]++;
	}
	printf("%lld",ans);
}

2.trie版

#include<cstdio>
#include<cstring>
using namespace std;
#define N 1000000+200
long long ti[N],d[N],las[N],trie[N][27];
long long tot,len,cnt,x,ans;
char s[N];
int main()
{
	freopen("bracket.in","r",stdin);
	freopen("bracket.out","w",stdout);
	scanf(" %s",s+1);
	len=strlen(s+1);
	cnt=1;
	x=1;
	ti[1]++;
	for(long long i=1;i<=len;i++)
	{
		long long k=s[i]-'a';
		if(d[tot]==k&&tot>0)
		{
			x=las[x];
			ti[x]++;
			ans+=ti[x]-1;
			tot--;
		}
		else
		{
			d[++tot]=k;
			if(!trie[x][k])
			{
				trie[x][k]=++cnt;
				las[trie[x][k]]=x;
			}
			x=trie[x][k];
			ti[x]++;
			ans+=ti[x]-1;
		}
	}
	printf("%lld",ans);
}