[BZOJ1879] [Sdoi2009]Bill的挑战

Description

Input

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

Output

如题

Sample Input

5
3 3
???r???
???????
???????
3 4
???????
?????a?
???????
3 3
???????
?a??j??
????aa?
3 2
a??????
???????
???????
3 2
???????
???a???
????a??

Sample Output

914852
0
0
871234
67018


容易想到设$large f[i][s]$表示正在填第i为,匹配的状态为s的方案数。

然后转移就很明显了,预处理出来每一位填每一个字母可以匹配的集合,然后可以快速转移。

这样做Luogu上AC了,但Bzoj的laji评测机过不去, 所以需要点优化。

首先小于k的状态不用转移,因为再怎么转移也不会让匹配成功的数目增多。

还有如果$large f[i][s]$是0,那么就不用它转移, 这样452msAC


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <bitset>
#include <ctime>
using namespace std;
#define reg register
#define mod 1000003
int T;
int n, m; 
char S[16][55];
int f[55][1<<15];
int g[55][500];
int bin[16];
int ans;

int main() 
{
    bin[0] = 1;for(reg int i = 1 ; i <= 15 ; i ++) bin[i] = bin[i-1] << 1;
    scanf("%d", &T);
    while(T--)
    {
        memset(f, 0, sizeof f);
        memset(g, 0, sizeof g);
        scanf("%d%d", &n, &m);
        for (reg int i = 1 ; i <= n ; i ++) scanf("%s", S[i] + 1);
        int len = strlen(S[1] + 1);
        
        for (reg int i = 1 ; i <= len ; i ++) 
            for (reg int k = 1 ; k <= n ; k ++)
                if (S[k][i] == '?')  
                    for (reg int j = 'a' ; j <= 'z' ; j ++)g[i][j] |= bin[k-1];
                else g[i][S[k][i]] |= bin[k-1];
        
        f[0][bin[n]-1] = 1;
        
        for (reg int i = 0 ; i < len ; i ++)
        {
            for (reg int s = 0 ; s <= bin[n] - 1 ; s ++)
            {
                if (!f[i][s]) continue;
                bitset <17> bit = s;
                if (bit.count() < m) continue;
                for (reg int j = 'a' ; j <= 'z' ; j ++)
                {
                    int sit = s & g[i+1][j];
                    f[i+1][sit] = (f[i+1][sit] + f[i][s]) % mod;
                }
            }
        }
        ans = 0;
        for (reg int s = 0 ; s <= bin[n] - 1 ; s++)
        {
            bitset <17> bit = s;
            if (bit.count() == m) ans = (ans + f[len][s]) % mod;
        }
        printf("%d
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/BriMon/p/9585303.html