Gym

来源:互联网 发布:android系统源码架构 编辑:程序博客网 时间:2024/05/17 23:28

Problem E  Passwords


It's that time of the year again when you go back to work and

need to choose new passwords for all your services. The rules
enforced by the system administrators are very strict, and the
password you choose must obey the following restrictions:
· It must contain only letters and digits.
 ·It must have between A and B characters (inclusive).
 ·It must have at least one lowercase letter, one uppercase letter and one digit.
 ·It cannot contain any word of a collection of forbidden words (the blacklist).
A word of the blacklist is considered to be contained in the password if it appears as a substring,
that is, if it occurs as a consecutive sequence of characters (regardless of it being upper or
lower case). For instance, swerc is a substring of SwErC, 2016swerc2016 or SWERC16, but it
is not a substring of ICPC or sw16erc.
Additionally, for the purposes of avoiding the blacklist, you cannot use l33t. Specically,
some digits can be interpreted as letters, namely the 0 ('o'), 1 ('i'), 3 ('e'), 5 ('s') and 7 ('t').
This implies that for example 5w3rC would be an occurrence of swerc, and that abcL337def
contains the word leet.
You cannot stop thinking about all these rules and you wonder how many dierent valid
passwords there are... Can you calculate how many passwords would obey these rules?


Task

Given a blacklist with N words and two integers A and B, your task is to compute the number
of dierent valid passwords that exist following the given constraints: made up of only letters
and digits; length between A and B (inclusive); at least one lowercase letter, one uppercase
letter, and one digit; no blacklisted substring. Since this number can be very big, compute it
modulo 1 000 003.


Input

The rst line contains two integers, A and B, specifying respectively the minimum and
maximum length of the password. The second line contains an integer N, the number of
words of the blacklist. The following N lines each contains a string Wi indicating a word in
the blacklist. These words are formed only by lowercase letters.

Constraints

3  A  B  20 Size of the password
0  N  50 Number of words in the blacklist
1  length(Wi)  20 Size of each blacklist word


Output

The output should contain a single line with an integer indicating the number of valid
passwords modulo 1 000 003. A valid password is one that respects all of the given constraints.


Sample Input

3 5
9
swerc
icpc
fbi
cia
bio
z
hi
no
yes


Sample Output

607886


Sample Explanation

In this case there are exactly 378 609 020 valid passwords and
378 609 020 mod 1 000 003 = 607 886 :
Some examples of valid passwords are: aA1, B23tT, 1g9K or B2j.
Some examples of invalid passwords are: aaA (it does not contain digits), 12a (it does not
contain upper case letters), a12A34 (length > 5) or bB10 (contains bio as substring).


Source

SWERC'2016  Universidade do Porto

Gym - 101174E


My Solution

题意:给出n个由小写字母模式串,用大写字母、小写字母、十进制数字构造的长度为[A, B]的字符串,

且满足一下限制条件:1、必须有至少一个大写字母至少一个小写字母和一个数字。

2、不包含任一模式串(不区分大小写)。

3、对于o、i、e、s、t,在模式串时和0、1、3、5、7不区分。

求构造出的满足条件的字符串种数。


AC自动机+额外的限制条件+状态压缩dp

首先这题的原始版本是 给出n模式串,构造不含任一模式串的长度为m的字符串种类数 http://blog.csdn.net/prolightsfxjh/article/details/54729646。

然后这题添加1、用大小写+数字进行构造+不区分大小写。

2、 构造出的字符串有至少一个大写字母至少一个小写字母和一个数字。

3、对于o、i、e、s、t,在模式串时和0、1、3、5、7不区分。

对于第二个条件,可以直接添加一维dp[8] 来状态压缩。

对于第一个条件则转移的时候直接转移2次即可,//mod( dp[ac.ch[j][k]][i][w | 1] += dp[j][i-1][w] );  mod( dp[ac.ch[j][k]][i][w | 2] += dp[j][i-1][w] );

对于第三个条件则如果是o、i、e、s、t 则在不是危险节点的时候额外转移一次,//mod( dp[ac.ch[j][k]][i][w | 4] += dp[j][i-1][w] ); 

其它数字则不管当前节点是否为危险节点都进行转移。

答案就是 sigma{dp[0 ~ ac.sz][[A, B]]}

复杂度 O(max(A, B) * len* n * 8 * CHAR_SIZE) == 4.16e6


#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <map>using namespace std;typedef long long LL;const int CHAR_SIZE = 26;const int MAX_SIZE = 1e3 + 8;const int MOD = 1000003;inline int mp(char ch){    return ch - 'a';}struct AC_Machine{    int ch[MAX_SIZE][CHAR_SIZE], danger[MAX_SIZE], fail[MAX_SIZE];    int sz;    void init(){        sz = 1;        memset(ch[0], 0, sizeof ch[0]);        memset(danger, 0, sizeof danger);    }    void _insert(char *s){        int n = strlen(s);        int u = 0, c;        for(int i = 0; i < n; i++){            c = mp(s[i]);            if(!ch[u][c]){                memset(ch[sz], 0, sizeof ch[sz]);                danger[sz] = 0;                ch[u][c] = sz++;            }            u = ch[u][c];        }        danger[u] = 1;    }    void _build(){        queue<int> Q;        fail[0] = 0;        for(int c = 0, u; c < CHAR_SIZE; c++){            u = ch[0][c];            if(u){Q.push(u); fail[u] = 0;}        }        int r;        while(!Q.empty()){            r = Q.front();            Q.pop();            danger[r] |= danger[fail[r]];            for(int c = 0, u; c < CHAR_SIZE; c++){                u = ch[r][c];                if(!u){ch[r][c] = ch[fail[r]][c]; continue; }                fail[u] = ch[fail[r]][c];                Q.push(u);            }        }    }}ac;char s[22];inline void mod(int &x){    x -= x / MOD * MOD;}int dp[MAX_SIZE][22][8];int main(){    #ifdef LOCAL    freopen("e.txt", "r", stdin);    //freopen("e.out", "w", stdout);    int T = 1;    while(T--){    #endif // LOCAL    //ios::sync_with_stdio(false); cin.tie(0);    int n, m, p; // n - > A, m -> B    scanf("%d%d%d", &n, &m, &p);    ac.init();    while(p--){        scanf("%s", s);        ac._insert(s);    }    int i, j, k, w;    memset(dp, 0, sizeof dp);    ac._build();    dp[0][0][0] = 1;    for(i = 1; i <= m; i++){        for(j = 0; j < ac.sz; j++){            for(w = 0; w < 8; w++){                if(dp[j][i-1][w] == 0) continue;                for(k = 0; k < CHAR_SIZE; k++){                    if(!ac.danger[ac.ch[j][k]]){                        mod( dp[ac.ch[j][k]][i][w | 1] += dp[j][i-1][w] );                        mod( dp[ac.ch[j][k]][i][w | 2] += dp[j][i-1][w] );                        if(k == 'o' - 'a' || k == 'i' - 'a' || k == 'e' - 'a' || k == 's' - 'a' || k == 't' - 'a'){                            mod( dp[ac.ch[j][k]][i][w | 4] += dp[j][i-1][w] ); // 0 1 3 5 7                        }                    }                }                mod( dp[0][i][w | 4] += dp[j][i-1][w] ); // 9                for(k = 1; k < 10; k++){// 2 4 6 8                    if(!(k&1)) mod( dp[0][i][w | 4] += dp[j][i-1][w] );                }            }        }    }    int ans = 0;    for(j = n; j <= m; j++){        for(i = 0; i < ac.sz; i++){            mod( ans += dp[i][j][8-1]);        }    }    printf("%d\n", ans);    #ifdef LOCAL    cout << endl;    }    #endif // LOCAL    return 0;}


  Thank you!

                                                                                                                                             ------from ProLights

原创粉丝点击