UVAlive 3490 AC自动机+(整数)高斯消元

来源:互联网 发布:php微信商城三级分销 编辑:程序博客网 时间:2024/06/05 14:07

题意:

题目链接:https://vjudge.net/problem/UVALive-3490
给出一个字符串S和前n个英文大写字母,组成一个字符串,当构造出子串S时停止,则该字符串期望长度是多少。


思路:

AC自动机+高斯消元,与HDU 5955一个套路:http://blog.csdn.net/bahuia/article/details/53034010
这题坑的时直接用double的高斯消元误差太大,连样例都出不来,必须改成整形的高斯消元,学习别人的写法,存个板子。


代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 100;struct ACauto {    int next[MAXN][26], fail[MAXN], end[MAXN];    int root, sz;    int newnode() {        for (int i = 0; i < 26; i++)            next[sz][i] = -1;        end[sz++] = 0;        return sz - 1;    }    void init() {        sz = 0;        root = newnode();    }    int idx(char c) {        return c - 'A';    }    void insert(char *buf) {        int len = strlen(buf);        int now = root;        for (int i = 0; i < len; i++) {            int id = idx(buf[i]);            if (next[now][id] == -1)                next[now][id] = newnode();            now = next[now][id];        }        end[now]++;    }    void build() {        queue <int> Q;        fail[root] = root;        for (int i = 0; i < 26; i++) {            if (next[root][i] == -1)                next[root][i] = root;            else {                fail[next[root][i]] = root;                Q.push(next[root][i]);            }        }        while (!Q.empty()) {            int now = Q.front(); Q.pop();            for (int i = 0; i < 26; i++) {                if (next[now][i] == -1)                    next[now][i] = next[fail[now]][i];                else {                    fail[next[now][i]] = next[fail[now]][i];                    Q.push(next[now][i]);                }            }        }    }} ac;int equ, var;LL a[MAXN][MAXN], x[MAXN];void Gauss()//表示用double版本的高斯消元求解,最后还原成整数的方法因为误差跪掉了....{    for(int i = 0; i < equ; i++)    {        int r = i;        while(r < equ && !a[r][i]) r++;        if(r != i)//找到第r列不是0的之后交换至r行        {            for(int j = 0; j < var; j++) swap(a[r][j], a[i][j]);            swap(x[r], x[i]);        }        for(int k = i + 1; k < equ; k++)            if(a[k][i])//将下面所有行的第i列变成0            {                LL tmp = a[k][i];//两组互相乘上对面的第i列的数作差即可                for(int j = i; j < var; j++) a[k][j] = a[k][j] * a[i][i] - tmp*a[i][j];                x[k] = x[k]*a[i][i] - tmp*x[i];            }    }    //对剩下的三角矩阵递推求解    for(int i = equ - 1; i >= 0; i--)    {        for(int j = i + 1; j < var; j++)            x[i] -= x[j]*a[i][j];        x[i] /= a[i][i];    }}char str[MAXN];int main() {    //freopen("in.txt", "r", stdin);    int T, cs = 0;    scanf("%d", &T);    while (T--) {        int n;        scanf("%d%s", &n, str);        ac.init();        ac.insert(str);        ac.build();        equ = var = ac.sz;        memset(a, 0, sizeof(a));        memset(x, 0, sizeof(x));        //cout << ac.sz << endl;        for (int u = 0; u < ac.sz - 1; u++) {            a[u][u] = n;            for (int id = 0; id < n; id++) {                int v = ac.next[u][id];                a[u][v] -= 1;            }            a[u][var] = n;            x[u] = n;        }        a[equ - 1][var - 1] = 1;        a[equ - 1][var] = 0;        x[equ - 1] = 0;        Gauss();        printf("Case %d:\n%lld\n", ++cs, x[0]);        if (T) puts("");    }    return 0;}
阅读全文
0 0
原创粉丝点击