2016ACM/ICPC亚洲区沈阳站H - Guessing the Dice Roll HDU - 5955 ac自动机+概率dp+高斯消元

http://acm.hdu.edu.cn/showproblem.php?pid=5955

题意:给你长度为l的n组数,每个数1-6,每次扔色子,问你每个串第一次被匹配的概率是多少

题解:先建成ac自动机构造fail数组,然后因为fail指针可能向前转移所以不能不能直接递推dp,需要高斯消元解方程,对于节点i,假设不是结束点而且能转移到它的点有a1,a2...an,那么dp[i]=1/6*dp[a1]+1/6*dp[a2]+...+1/6*a[n],然后我们可以列出n个方程,高斯消元然后找到每个串结尾点的概率就是答案了

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

const double g=10.0,eps=1e-12;
const int N=100+10,maxn=20000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;

int l;
double a[N][N],ans[N];
void gauss(int n)
{
    for(int i=1;i<n;i++)
    {
        if(a[i][i]==0)
        {
            int id=0;
            for(int j=i+1;j<=n;j++)
                if(a[j][i]!=0)
                    id=j;
            for(int j=i;j<=n+1;j++)
                swap(a[i][j],a[id][j]);
        }
        for(int j=i+1;j<=n;j++)
        {
            double t=a[j][i]/a[i][i];
            for(int k=i;k<=n+1;k++)
                a[j][k]-=(a[i][k]*t);
        }
    }
//    for(int i=1;i<=n;i++)
//    {
//        for(int j=1;j<=n+1;j++)
//            printf("%.12f ",a[i][j]);
//        puts("");
//    }
    for(int i=n;i>=1;i--)
    {
        for(int j=i+1;j<=n;j++)
            a[i][n+1]-=ans[j]*a[i][j];
        ans[i]=a[i][n+1]/a[i][i];
    }
}
char s[N];
struct ACM{
    int root,tot;
    int Next[N][10],fail[N],End[N];
    int newnode()
    {
        memset(Next[tot],-1,sizeof Next[tot]);
        End[tot]=0;
        return tot++;
    }
    void init()
    {
        tot=0;
        root=newnode();
    }
    void ins(int i)
    {
        int now=root;
        for(int i=0,x;i<l;i++)
        {
            scanf("%d",&x);x--;
            if(Next[now][x]==-1)
                Next[now][x]=newnode();
            now=Next[now][x];
        }
        End[now]=i;
    }
    void build()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<6;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();
            if(End[fail[now]])End[now]=End[fail[now]];
            for(int i=0;i<6;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]);
                }
            }
        }
    }
    void solve()
    {
        memset(a,0,sizeof a);
        a[1][tot+1]=-1.0;
        for(int i=0;i<tot;i++)
        {
            a[i+1][i+1]=-1.0;
            if(End[i])continue;
            for(int j=0;j<6;j++)a[Next[i][j]+1][i+1]+=1.0/6;
        }
//        for(int i=1;i<=tot;i++)
//        {
//            for(int j=1;j<=tot+1;j++)printf("%.5f ",a[i][j]);
//            puts("");
//        }
        gauss(tot);
        bool ok=0;
        for(int i=0;i<tot;i++)
        {
            if(End[i])
            {
                if(!ok)printf("%.6f",ans[i+1]);
                else printf(" %.6f",ans[i+1]);
                ok=1;
            }
        }
        puts("");
    }
}ac;
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        ac.init();
        int n;
        scanf("%d%d",&n,&l);
        for(int i=0;i<n;i++)ac.ins(i+1);
        ac.build();
        ac.solve();
    }
    return 0;
}
/***********************
1
2 2
1 1
2 1
***********************/
View Code

猜你喜欢

转载自www.cnblogs.com/acjiumeng/p/8988446.html
今日推荐