洛谷 P2167 [SDOI2009]Bill的挑战

题目描述

输入输出格式

输入格式:

本题包含多组数据。 第一行:一个整数T,表示数据的个数。 对于每组数据: 第一行:两个整数,N和K(含义如题目表述)。 接下来N行:每行一个字符串。

输出格式:

1 2 1 a? ?b

输入输出样例

输入样例#1:
50
输出样例#1:
对于30%的数据,T ≤ 5,M ≤ 5,字符串长度≤ 20;

对于70%的数据,T ≤ 5,M ≤ 13,字符串长度≤ 30;

对于100%的数据,T ≤ 5,M ≤ 15,字符串长度≤ 50。

真是玄学题
经历了从50分到70分再到AC
一开始看到觉得是带通配符的AC自动机状压DP,一看要求长度都一样,好像直接DP就行呀?
然后写了最朴素的DP,dp[i][j]表示转移到第i个字符,目前能匹配上的状态为j的方案数,然后枚举下一位是什么,与所有字符串进行比较转移即可
这样的复杂度是 $ O(26TLn*2^n) $ ,能有50分
然后可以发现与所有字符串比较是很愚蠢的,进行了很多重复计算,我们可以预处理出每一位所有字符串匹配某个字符的结果,压在一个int里,转移时直接按位与即可
这样复杂度是
$ O(26TL*2^n) $ ,能有70分
然后你把它数字带进去发现,它乘出来是26*5*50*2^15约等于2e8,这是什么意思?这意思就是稍微卡一卡就能过了。
DP怎么稍微卡一卡呢?你想DP倒过来就是记忆化搜索,搜索可以剪枝啊,于是我们尝试剪一剪枝。
怎么剪枝呢?加上如果在遍历到某个状态dp[i][j]时,如果dp[i][j]==0就不转移
事实上这个效果好得出奇,速度快了10倍都不止,至此获得100分
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <string>
 6 #include <cstring>
 7 #include <cmath>
 8 #include <map>
 9 #include <stack>
10 #include <set>
11 #include <vector>
12 #include <queue>
13 #include <time.h>
14 #define eps 1e-7
15 #define INF 0x3f3f3f3f
16 #define MOD 1000003
17 #define rep0(j,n) for(int j=0;j<n;++j)
18 #define rep1(j,n) for(int j=1;j<=n;++j)
19 #define pb push_back
20 #define set0(n) memset(n,0,sizeof(n))
21 #define ll long long
22 #define ull unsigned long long
23 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
24 #define max(a,b) (a>b?a:b)
25 #define min(a,b) (a<b?a:b)
26 #define print_runtime printf("Running time:%.3lfs
",double(clock())/1000.0)
27 #define TO(j) printf(#j": %d
",j);
28 //#define OJ
29 using namespace std;
30 const int MAXINT = 100010;
31 const int MAXNODE = 100010;
32 const int MAXEDGE = 2*MAXNODE;
33 char BUF,*buf;
34 int read(){
35     char c=getchar();int f=1,x=0;
36     while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
37     while(isdigit(c)){x=x*10+c-'0';c=getchar();}
38     return f*x;
39 }
40 char get_ch(){
41     char c=getchar();
42     while(!isalpha(c)) c=getchar();
43     return c;
44 }
45 //------------------- Head Files ----------------------//
46 
47 int dp[51][1<<15],n,k,l,cnt[1<<15];
48 unsigned int val[51][26];
49 char s[15][60];
50 void get_input();
51 void work();
52 int main() {
53     int T=read();
54     rep1(i,(1<<15)-1){
55         cnt[i]=cnt[i-(i&-i)]+1;
56     }
57     while(T--){
58         get_input();
59         work();
60     }
61     return 0;
62 }
63 void work(){
64     int mx = (1<<n);
65     memset(val,0xffff,sizeof(val));
66     rep1(i,l){
67         rep0(j,26){
68             rep0(k,n){
69                 if(s[k][i]!='?'&&s[k][i]!='a'+j) val[i][j]&=(~(1<<k));
70             }
71         }
72     }
73     dp[0][(1<<n)-1] = 1;
74     rep0(i,l){
75         rep0(j,mx){
76             if(dp[i][j]==0) continue;
77             rep0(k,26){
78                 int t = j;
79                 t&=val[i+1][k];
80                 dp[i+1][t]+=dp[i][j];
81                 dp[i+1][t]%=MOD;
82             }
83         }
84     }
85     ll ans = 0;
86     rep0(i,mx) if(cnt[i]==k) ans+=dp[l][i];
87     printf("%lld
",ans%MOD);
88 }
89 void get_input(){
90     memset(dp,0,sizeof(dp));
91     n=read();k=read();
92     rep0(i,n) scanf("%s",s[i]+1);
93     l=strlen(s[0]+1);
94 }


 

原文地址:https://www.cnblogs.com/LoveYayoi/p/6932869.html