2017.7.27 bill的挑战 失败总结

做了两个状压dp,有点门路了

  就是说一般状压dp都需要枚举前面的状态,然后利用插数的思想递推,一般想清楚转移就差不多了  ,它就是利用状态把等效的情况压在了一起,和位运算的优势来dp


这个题一开始老是想压每一个串的字符,但实际上2^50怎么也不行了,,

所以一定要看到15

既然是串数被压缩,那我们肯定不能枚举串了,我们应该想办法通过位置递推来完成压串的dp

对于每一个字符,我们需要知道每一个位置上能填的串的情况


这个题有一个匹配数,所以f存匹配的个数

注意到串的字符匹配位数有无序性(无论什么位置匹配,所有都匹配了就行)

所以就可以一并考虑,在每一个位置枚举所有可能填的字符,转移到下一阶段做起点

这个dp的独特之处就是利用字符的枚举构造T并同时筛掉每次枚举不合法的串

以前不合法的,之后一定不合法。


码:

#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
#define P 1000003
int f[55][1<<16],pei[55][55],n,K,T,ans;
char str[55][55];
int main()
{
	scanf("%d",&T);
	while(T--)
	{  ans=0;
		memset(pei,0,sizeof(pei));
		memset(f,0,sizeof(f));
		scanf("%d%d",&n,&K);
		for(int i=1;i<=n;i++)scanf("%s",str[i]+1);
		int len=strlen(str[1]+1);
		for(int i=1;i<=len;i++)
		for(int j=1;j<=26;j++)
		for(int k=1;k<=n;k++)
		{
		if(str[k][i]=='?'||str[k][i]-'a'+1==j)pei[i][j]=pei[i][j]|(1<<(k-1));				
		} 
		
		f[0][(1<<n)-1]=1;
        for(int i=0;i<len;i++)
    	for(int k=0;k<=(1<<n)-1;k++)    
		if(f[i][k]) 
		for(int j=1;j<=26;j++)
		{  //cout<<"l";
			f[i+1][pei[i+1][j]&k]=(f[i+1][pei[i+1][j]&k]+f[i][k])%P;			
		}
	for(int i=0;i<=(1<<n)-1;i++)
	{
		int k=i,js=0;
		while(k)
		{
			if(k&1==1)js++;
			k>>=1;
		}
		if(js==K)ans+=f[len][i],ans%=P;
		
	}
printf("%d\n",ans);
	}
	
 } 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值