HDU 5357

     这一题好神啊,看了半天题解还是不会做。

设a[i]表示以i开头的合法括号序列的个数,b[i]表示以i结尾的合法括号序列的个数,a只考虑左括号,B反之。

设up[i]表示包括i的极小匹配序列的左端且up[i]!=i;

记match[i]表示i括号匹配的位置。

那么ans[i]=ans[match[i]]=ans[up[i]]+a[i]*b[match[i]];

       ab怎么求呢?

a[i]=a[match[i]+1]+1,b[i]=b[match[i]-1]+1;

   至于up,当遇到一个右括号时,弹出栈顶的左括号,这是vis,此时栈顶的元素便是up;

至此问题便完美解决了。代码好丑。WA了许许多多次。%%__debug大神。

#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<stack>
using namespace std;
const int MAXN=1e6+20;
const int zqf=1000000007;
stack<int> st;
int vis[MAXN],a[MAXN],b[MAXN],up[MAXN],t;
long long ans[MAXN];
int len;
string s;
void clear(int *t,int k)
{
	for(int i=0;i<len+10;i++)t[i]=k;
}
void clearL(long long *t)
{
	for(int i=0;i<len+10;i++)t[i]=0;
}
void init()
{
	clearL(ans);
	clear(a,0);
	clear(b,0);
	clear(vis,-1);
	clear(up,-1); 
	while(!st.empty())st.pop();
}
void make_vis()
{
	int p=0;
	for(int i=0;i<s.size();i++)
	{
		if(s[i]=='(')
		{st.push(i);p=i;break;}
	}p++;
	while(p<=s.size()-1)
	{
		if(s[p]=='(')st.push(p);
		else
		{
			int k=st.empty()?0:st.top();
			if(st.empty())
			   {p++;continue;}
			vis[p]=k;
			vis[k]=p;
			if(!st.empty())st.pop();
			up[p]=up[vis[p]]=st.empty()?-1:st.top();
		}
		p++;
	}
}
void Read(int& x)
{
	x=0;
	char c;int flag=0;
	while(c=getchar())
	{
		if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
		else if(flag)break;
	}
}
int main()
{
	freopen("rand.out", "r", stdin);
    freopen("w.out", "w", stdout);
	Read(t);
	while(t--)
	{
		char ss[MAXN]={};
		scanf("%s",ss);
		string sss(ss);
		s=sss;
		len=s.size();
		init();
		long long loe=0;
		make_vis();
		for(int i=0;i<s.size();i++)
			if(s[i]==')'&&vis[i]!=-1)
				b[i]=b[vis[i]-1]+1;
		for(int j=s.size()-1;j>=0;j--)
		   	if(s[j]=='('&&vis[j]!=-1)
		   	    a[j]=a[vis[j]+1]+1;
		for(int i=0;i<s.size();i++)
		{
			if(up[i]!=-1&&!ans[i]&&vis[i]!=-1)
			   ans[i]=ans[vis[i]]=ans[up[i]]+(long long)a[i]*b[vis[i]];
			else if(up[i]==-1&&!ans[i]&&vis[i]!=-1)
				ans[i]=ans[vis[i]]=(long long)a[i]*b[vis[i]];
		}
		for(int i=0;i<s.size();i++)
		{
			loe=(loe+ans[i]*(i+1)%zqf);
		}
		printf("%I64d\n",loe);
	}
}	

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值