【[SDOI2009]Bill的挑战】

这个复杂度能过真是令人惊讶

本来准备是打个暴力看看能水多少分的,但是就\(A\)

那也就是说我用\(50*2^{15}*26*15\)的复杂度跑过了五组数据

真是玄学

首先字符串题目的套路就是我们需要存一个状态表示匹配到第几位

\(n<=15\)一眼状压

于是我们的状态是\(dp[i][S]\)表示在\(S\)这个状态下的所有字符串都匹配到了\(i\)位的方案数

于是我们可以刷表转移

由于字符集大小只有\(26\),所以我们可以对于每一个状态枚举一下这个状态往下匹配匹配哪一位

之后在枚举一下当前状态里的所有串,我们就可以得到这一个状态往下扩展的状态是什么了

是个非常大的,但是跑不满的复杂度

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
const int mod=1000003;
int T,n,m,len;
char S[16][51];
inline int cnt(int x)
{
	int tot=0;
	while(x) tot+=(x&1),x>>=1;
	return tot;
}
int dp[51][32768];
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(re int i=1;i<=n;i++)
			scanf("%s",S[i]+1);
		int len=strlen(S[1]+1);
		memset(dp,0,sizeof(dp));
		int N=(1<<n);
		dp[0][N-1]=1;
		for(re int i=0;i<len;i++)
			for(re int j=0;j<N;j++)
			{
				if(!dp[i][j]) continue;
				for(re char k='a';k<='z';k++)
				{
					int f=j;
					for(re int p=1;p<=n;p++)
					if(j&(1<<(p-1))) if(S[p][i+1]!='?'&&S[p][i+1]!=k) f^=(1<<(p-1));
					dp[i+1][f]=(dp[i+1][f]+dp[i][j])%mod;
				}
			}
		int ans=0;
		for(re int i=0;i<N;i++)
		if(cnt(i)==m) ans=(ans+dp[len][i])%mod;
		std::cout<<ans;
		putchar(10);
	}
	return 0;
}
posted @ 2019-01-01 21:39  asuldb  阅读(199)  评论(0编辑  收藏  举报