3857. 【NOIP2014八校联考第3场第1试10.4】反抗希碧拉系统续

Description

虽然一科的反抗行动失败了,但那次行动已使反抗希碧拉系统的观念深入人心,而作为分析官的你也找到了系统的某处漏洞,机会依然存在,你要为下一次反抗做好准备。
直接使用电磁脉冲破坏系统在上次被证明是不可行的,现在只能试图渗透进系统寻找突破口。你现在可以从漏洞监听到中枢中每个单元大脑间的通信,并筛选出其中符合某规则的一些进行更深入的分析。规则可以描述为一个特殊的正则表达式,有如下递归定义:
    元素:=“[”+字符集+“]”,表示匹配字符集中的任意一个字符。字符集中的字符都是小写英文字母。“+”表示字符串的连接。
    表达式:=元素 或 表达式+表达式 或 “(”+表达式+“)”+“+”。相连的表达式表示匹配连续的字符。“+”表示前面括号中的内容出现一次或多次。
    例如:表达式[a][b]匹配ab;表达式[ab][c]匹配ac或bc;表达式([a][b])+([c])+可以匹配“abc”、“ababc”、“ababccc”等串。
    你的同事决定使用巨型计算机穷举每个符合要求的定长字符串(通信)并分析其性质。你对这种方法持怀疑态度,较长的运算时间以及可能比中枢还大的耗电量必然会引起系统的怀疑。你需要计算有多少满足要求的字符串以估算计算所需时间,你坚信分析正则表达式作为一项分析官必备的技能并不会太困难。 

Input

第一行一个字符串,表示该表达式。
第二行一个正整数M表示穷举的字符串的长度。

Output

一行,仅一个整数,表示符合要求的字符串数量对2^32取模。

Sample Input

[a](([b])+[c]([d])+[ad])+
5

Sample Output

2

Data Constraint


对于所有数据另外满足以下条件
1:不存在空的[]或()
2:元素中的字符集没有重复字符
3:不存在连续的+,例如(([a])+)+
4: +前一定是),)后一定是+

Solution

构建自动机。

一个元素向后面一个元素连一条有向边,对于“+”就相当于一个元素中的最后一个字符又重新走到开头字符,那么就相当于重新走这些元素一遍,那么就从最后一个元素向括号内第一个元素连一条有向边。

那么这个自动机就构造好了。

之后我们考虑如何求方案数。

设f[i][S]表示构造的序列长度为i,可能结尾的元素二进制压缩后状态为S的方案数,设a[S][S']表示在状态S转移到状态S'的贡献。

对于a的求法,首先可以枚举状态S,然后枚举一个字符c表示接下来要添加的字符为c,再枚举转态S中每一个所选的元素,并判断,如果这个元素所能到达的元素中能有字符c,那么a[S][S']++。

接下来就有了转移方程:

f[i][S]=f[i-1][S']*a[S'][S]

时间复杂度O(n*2^10)。

考虑优化方程,注意到每次我们做的事情是一样的,那么容易想到用矩阵乘法优化方程。

最后答案是sum{f[m][S]}其中S只需要包含n这个元素。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
char s[1000];
I len,n,m,e[9][9],st[9],h[9][30],tp=0;
unsigned int ans[40][40],a[40][40],f[40];
void mul(){
	mem(ans,0);I x=(1<<n)-1;
	F(j,1,x){
		F(k,1,x) ans[1][j]=(ans[1][j]+f[k]*a[k][j]);
	}
	F(j,1,x) f[j]=ans[1][j];
}
void tim(){
	mem(ans,0);I x=(1<<n)-1;
	F(i,1,x){
		F(j,1,x){
			F(k,1,x) ans[i][j]=(ans[i][j]+a[i][k]*a[k][j]);
		}
	}
	F(i,1,x){
		F(j,1,x) a[i][j]=ans[i][j];
	}
}
I main(){
	scanf("%s",s+1);len=strlen(s+1);
	F(i,1,len){
		if(s[i]=='[') ++n;
		else if(s[i]=='(') st[++tp]=n+1;
		else if(s[i]==')') e[n][st[tp--]]=1;
		else if(s[i]>='a'&&s[i]<='z') h[n][s[i]-'a'+1]=1;
	}
	F(i,1,n-1) e[i][i+1]=1;
	F(i,1,(1<<n)-1){
		F(c,1,26){
			I s=0;
			F(j,1,n) if((i>>j-1)&1){
				F(k,1,n){
					if(e[j][k]&&h[k][c]) s|=1<<k-1;	
				}
			}
			if(s) a[i][s]++;
		}
	}
	F(i,1,26) f[1]+=h[1][i];
	scanf("%d",&m);m--;
	while(m){
		if(m&1) mul();
		tim();
		m>>=1;
	}
	ans[0][0]=0;
	F(i,1,(1<<n)-1) if((i>>n-1)&1){ans[0][0]=(ans[0][0]+f[i]);}
	printf("%u\n",ans[0][0]);
	return 0;
}
发布了199 篇原创文章 · 获赞 201 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/104031297
今日推荐