UVaLive 3490 - Generator (AC自动机 期望DP 高斯消元)

49 篇文章 0 订阅
39 篇文章 0 订阅

UVALive - 3490

Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

[]   [Go Back]   [Status]  

Description

Download as PDF

We can generate a random string by generating a sequence of random characters and concatenating them together. Each character is chosen independently from the first n letters in the English alphabet with equal probability. Only capital letters are used in this problem. The generation is stopped as soon as a specific pattern occurs in the random string.

Your task is to predict the expected length of the generated string.

Input

Standard input will contain multiple test cases. The first line of the input is a single integer T(1$ \le$T$ \le$10) which is the number of test cases.T test cases follow, each preceded by a single blank line.

Each test case consists of a single integer N(1$ \le$N$ \le$26) which is the number of letters used, and a pattern, which is a non-empty string consisting of letters chosen from the first N upper case English letters. The length of any pattern will not exceed 12.

Output

Results should be directed to standard output. Start each case with ``Case # : " on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.

For each test case, print the expected length of the generated random string.

Sample Input

5

2 A

2 ABA

3 AAAAA

26 ACMICPC

26 ZJUZJU

Sample Output

Case 1:
2

Case 2:
10

Case 3:
363

Case 4:
8031810176

Case 5:
308933352

Source

[]   [Go Back]   [Status]  




题意:

从空串开始,我们可以不断地从前n个大写字母中随机选出字母,然后加到串的末尾,直到这个串包含一个给定的字符串时停止。求停止时字符串长度的期望。


构造出状态机,因为只有一个字符串,所以只有strlen(s)+1个节点

dp[i]表示i节点到达结束需要添加字符数期望

dp[i] =∑(dp[j] / m) + 1    j表示i添加一个字符c到达的节点。m表示可选字符数。

直接高斯消元解。

注意这题的精度问题,等式同时乘m,高斯消元的时候里面也要同时乘A[i][i]看代码




#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif

#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)

const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));

const int maxn = 20;
typedef LL Matrix[20][20];

const int MAX_NODE = 20;
const int SIGMA_SIZE = 27;

char str[maxn];
Matrix MA;

struct ACAutomata {
    int ch[MAX_NODE][SIGMA_SIZE];
    bool val[MAX_NODE];
    int f[MAX_NODE];
    int sz;

    void init() {
        sz = 1; memset(ch[0], -1, sizeof(ch[0]));
        val[0] = false;
    }

    int idx(char c) {
        return c - 'A';
    }

    void insert(char * s) {
        int n = strlen(s);
        int u = 0;
        for (int i=0; i<n; i++) {
            int c = idx(s[i]);
            if(-1 == ch[u][c]) {
                memset(ch[sz], -1, sizeof(ch[sz]));
                val[sz] = false;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = true;
    }

    void build() {
        queue<int> Q;
        f[0] = 0;
        for (int i=0; i<SIGMA_SIZE; i++) {
            int u = ch[0][i];
            if(u != -1) { Q.push(u); f[u] = 0; }
            else ch[0][i] = 0;
        }
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            if(val[f[u]]) val[u] = true;
            for (int c=0; c<SIGMA_SIZE; c++) {
                int v = ch[u][c];
                if(-1 != v) {
                    Q.push(v);
                    f[v] = ch[f[u]][c];
                } else {
                    ch[u][c] = ch[f[u]][c];
                }
            }
        }
    }

    void getMatrix(Matrix A, int n, int m) {
        memset(A, 0, sizeof(A));
        for(int i=0; i<n-1; i++) {
            for(int j=0; j<m; j++) {
                int to = ch[i][j];
                A[i][to] += 1;
            }
            A[i][i] -= m;
            A[i][n] = -m;
        }
        A[n-1][n-1] = 1;
        A[n-1][n] = 0;
    }
} ac;

void gauss(Matrix A, int n) {
    int i, j, k, r;
    for(i = 0; i < n; i++) {
        r = i;
        while(r < n && !A[r][i]) r++; // 这里用abs会很溢出
        if(r != i) for(j = 0; j <= n; j++) swap(A[r][j], A[i][j]);
        for(k = i+1; k < n; k++) if(A[k][i]) {
            LL f = A[k][i]; // 这里乘了A[i]i]
            for(j = i; j <= n; j++) {
                A[k][j] = A[k][j] * A[i][i] - f * A[i][j];
            }
        }
    }
    for(i = n-1; i >= 0; i--) {
        for(j = i+1; j < n; j++) {
            A[i][n] -= A[j][n] * A[i][j];
        }
        A[i][n] /= A[i][i];
    }
}

int main() {
    int T;

    scanf("%d", &T);
    for(int kase=1; kase<=T; kase++) {
        int n;
        if(kase > 1) putchar('\n');
        scanf("%d%s", &n, str);
        ac.init();
        int len = strlen(str);
        ac.insert(str);
        ac.build();
        memset(MA, 0, sizeof(MA));
        int m = len + 1;
        ac.getMatrix(MA, m, n);
        gauss(MA, m);
        LL ans = MA[0][m];
        printf("Case %d:\n%lld\n", kase, ans);
    }

    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值