zoukankan      html  css  js  c++  java
  • 【题解】[SDOI2009]Bill的挑战

    [SDOI2009]Bill的挑战

    ( ext{Solution:})

    最初的 naive 想法是直接枚举子集算出每个子集中全部匹配的对应 (T) 串的个数,但是脑残到最后写完才反应过来会算重……

    但好像用二项式反演还能搞回来(雾)

    考虑 dp : 设 (dp[i][j]) 表示填充好 ([1,i]) 的长度,能匹配的子集状态是 (j) 的方案数。

    那么可以考虑用刷表法,枚举 (i+1) 位置填什么。一共 (26) 种组合。所以可以预处理出 (i) 位置能匹配字符 (j) 的状态集合,转移就可以是:

    [ ext{dp[i+1][j&state]+=dp[i][j]} ]

    就是对能匹配的集合求交集。

    于是这样的方案数一定是不重复的,因为每一次填上位置的字符都不同。

    不是说匹配到的字符串不同,而是我们自己构造出的 (T) 是不同的。

    重点在于让你每次构造出来的 (T) 都是不同的,这样才会保证不重不漏。

    从这角度出发,进而启发我们对字符串 (T) 进行 (dp),状态是和 (T) 息息相关的。

    重点在于要反思设计状态后注意一定不能把状态给算重复了,一定要考虑最容易算重的是什么。

    这个时候往往可以考虑一下状态对它设计,这样更有利于我们对它去重计数的处理。

    傻逼错误:数组开小了,调了半天,下次写代码就直接把数组拉到最不可能出错的大小就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1000003;
    inline int Mod(int x) {
    	return (x>=mod?(x-mod):(x<0?(x+mod):x));
    }
    inline int Max(int x,int y) {
    	return x>y?x:y;
    }
    inline int Min(int x,int y) {
    	return x<y?x:y;
    }
    inline int Add(int x,int y) {
    	return Mod(x+y);
    }
    inline int Mul(int x,int y) {
    	return 1ll*Mod(x)*Mod(y)%mod;
    }
    int T,n,dp[51][1<<17],len,K;
    int match[51][26];
    char A[17][60];
    inline int pop_count(int x) {
    	int res=0;
    	while(x!=0) {
    		res+=x&1;
    		x>>=1;
    	}
    	return res;
    }
    inline void Clear() {
    	memset(dp,0,sizeof dp);
    	memset(match,0,sizeof match);
    }
    int main() {
    	freopen("111.txt","r",stdin);
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d",&n,&K);
    		Clear();
    		for(int i=1; i<=n; ++i) {
    			scanf("%s",A[i]+1);
    		}
    		len=strlen(A[1]+1);
    		int w=(1<<n)-1;
    		dp[0][w]=1;
    		for(int i=1; i<=len; ++i) {
    			for(int j=0; j<26; j++) {
    				for(int k=1; k<=n; k++) {
    					if(A[k][i]=='?'||A[k][i]-'a'==j) {
    						match[i][j]|=(1<<(k-1));
    					}
    				}
    			}
    		}
    		for(int i=0; i<len; ++i) {
    			for(int j=0; j<(1<<n); ++j) {
    				for(int k=0; k<26; ++k) {
    					int state=j&match[i+1][k];
    					dp[i+1][state]+=dp[i][j];
    					if(dp[i+1][state]>=mod)dp[i+1][state]-=mod;
    				}
    			}
    		}
    		int ans=0;
    		for(int i=0; i<(1<<n); ++i) {
    			if(__builtin_popcount(i)==K) {
    				ans=ans+dp[len][i];
    				if(ans>=mod)ans-=mod;
    			}
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    判断文件结束,feof……
    第五篇 分治思想(例子待加)
    第四篇 枚举思想
    第三篇 贪心思想
    第二篇 递归思想
    第一篇 递推思想
    爬虫系列
    整数划分问题
    html中a标签做容器的问题
    H5学习小结——div+css创建电子商务静态网页
  • 原文地址:https://www.cnblogs.com/h-lka/p/15002654.html
Copyright © 2011-2022 走看看