JSOI 2009 BZOJ 1444 有趣的游戏

题面

题目描述

小阳阳发明了一个有趣的游戏:有n个玩家,每一个玩家均有一个长度为 l 的字母序列,任何两个玩家的字母序列不同。共有m种不同的字母,所有的字母序列都由这m种字母构成,为了方便,我们取大写字母的前。个字母。例如。m =3 , l = 4 , ABAA , CBCA 为两个合法的字母序列。现在由小阳阳来操控一台神奇的机器,每个时刻机器会随机产生一个字母,其中第i种字母随机出来的概率为pi/qi,显然 sum(pi/qi)=1 。这样T个时刻后机器会产生一个长度为 T 的字母序列。如果某个时刻某个玩家发现自己的字母序列在机器产生的字母序列中出现了,“出现”的定义是玩家的字母序列是机器产生的字母序列中连续的一段,那么我们称这个玩家获胜,游戏结束。现在小阳阳感兴趣的一个问题是,每个玩家分别有多大的概率能获得这场游戏的胜利呢?

输入格式

第一行有三个正整数n,l,m表示有n个人,每个人的字母序列长度为l,共有m个字母。
接下来m行,每行有两个非负整数p,q,表示随机到第i个字母的概率为p/q(0<=p<=q<=10,(p,q)=1)。数据保证m个字母的随机概率之和为1。
接下来n行,每行有一个长度为l的字母序列,表示第i个人的字母序列。数据保证所有的字母为大写字母的前m个且没有两个字母序列完全相同。

输出格式

包含n行,每行包含一个实数,表示第i个人获胜的概率,输出结果四舍五入到两位小数。

样例输入1

3 2 2
1 2
1 2
AB
BA
AA

样例输出1

0.25
0.50
0.25

样例输入2

3 4 2
1 2
1 2
AABA
ABAA
BAAA

样例输出2

0.31
0.33
0.37

样例说明1

两种字母 A 和 B ,概率均为 1/2。若前两个字母为 AB , BA 或AA,均有一个人获胜,获胜概率为 1 / 4 ;若前两个字母为 BB ,那么之后随机到 BBA , BBBA , BBBB 入都一定是 BA 获胜。因此 BA 的获胜概率为 1/4 + 1/4 = 1/2 。

样例说明 2

三个人的获胜概率分别为 4/13 , 17/52 , 19/52 ,注意输出结果四舍五入到两位小数。、

数据范围

100%的数据保证, n , l, m≤ 10.

题解

涉及概率 / 期望的题, 无非就是概率转期望, 期望转概率, DP一下就好了.
比如说这一题, 我们只需要建立trie图, 求出每个节点的经过的期望次数即可.
注意, 当一个节点的儿子为NULL时, 应该把这个概率加到根节点上.

#include <cstdio>
#include <cstring>
#include <deque>
#include <algorithm>

const int N = 10, M = 10, L = 10;
int n, l, m;
double p[M];
struct matrix
{
    int n;
    double a[N * L][N * L + 1];
    inline matrix()
    {
        memset(a, 0, sizeof(a));
    }
    inline void gauss()
    {
        for(int i = 0; i < n; ++ i)
        {
            int p;
            for(p = i; p < n && a[p][i] == 0; ++ p);
            if(p ^ i)
                for(int j = 0; j <= n; ++ j)
                    std::swap(a[i][j], a[p][j]);
            for(int j = 0; j < n; ++ j)
                if(j ^ i)
                {
                    double tmp = a[j][i] / a[i][i];
                    for(int k = 0; k <= n; ++ k)
                        a[j][k] -= a[i][k] * tmp;
                }
        }
    }
}A;
struct ACautomaton
{
    int cnt;
    struct node
    {
        node *suc[10], *fl;
        int ed, id;
        inline node(int _id)
        {
            for(int i = 0; i < 26; ++ i)
                suc[i] = NULL;
            ed = 0;
            id = _id;
        }
    }*rt;
    inline ACautomaton()
    {
        cnt = 0;
        rt = new node(cnt ++);
        rt->fl = rt;
    }
    inline int insert(char *str, int len, int id)
    {
        node *u = rt;
        for(int i = 0; i < len; u = u->suc[str[i] - 'A'], ++ i)
            if(u->suc[str[i] - 'A'] == NULL)
                u->suc[str[i] - 'A'] = new node(cnt ++);
        u->ed = 1;
        return u->id;
    }
    inline void build()
    {
        std::deque<node*> que;
        que.clear();
        for(int i = 0; i < 26; ++ i)
            if(rt->suc[i] != NULL)
                rt->suc[i]->fl = rt, que.push_back(rt->suc[i]), A.a[rt->suc[i]->id][0] = p[i];
            else if(i < m)
                A.a[0][0] += p[i];
        for(; ! que.empty(); que.pop_front())
        {
            node *u = que.front();
            for(int i = 0; i < 26; ++ i)
                if(u->suc[i] != NULL)
                {
                    if(! u->ed)
                        A.a[u->suc[i]->id][u->id] = p[i];
                    node *p = u->fl;
                    for(; p != rt && p->suc[i] == NULL; p = p->fl);
                    u->suc[i]->fl = p->suc[i] == NULL ? p : p->suc[i];
                    que.push_back(u->suc[i]);
                }
                else
                {
                    u->suc[i] = u->fl->suc[i];
                    if(u->suc[i] != NULL && ! u->ed)
                        A.a[u->suc[i]->id][u->id] = p[i];
                    else if(i < m && ! u->ed)
                        A.a[0][u->id] += p[i];
                }
        }
        A.n = cnt;
        A.a[0][cnt] -= 1;
        for(int i = 0; i < cnt; ++ i)
            A.a[i][i] += -1;
    }
}ACA;
int main()
{

    #ifndef ONLINE_JUDGE
    freopen("BZOJ1444.in", "r", stdin);
    freopen("BZOJ1444.out", "w", stdout);
    #endif

    scanf("%d%d%d", &n, &l, &m);
    for(int i = 0; i < m; ++ i)
    {
        int x, y;
        scanf("%d%d\n", &x, &y);
        p[i] = (double)x / y;
    }
    static int ed[N];
    for(int i = 0; i < n; ++ i)
    {
        static char str[L];
        scanf("%s", str);
        ed[i] = ACA.insert(str, l, i);
    }
    ACA.build();
    A.gauss();
    for(int i = 0; i < n; ++ i)
        printf("%.2lf\n", A.a[ed[i]][A.n] / A.a[ed[i]][ed[i]] == 0 ? 0 : A.a[ed[i]][A.n] / A.a[ed[i]][ed[i]]);
}

转载于:https://www.cnblogs.com/ZeonfaiHo/p/7147230.html

本项目是一个基于SSM(Spring+SpringMVC+MyBatis)后端框架与Vue.js前端框架开发的疫情居家办公系统。该系统旨在为居家办公的员工提供一个高效、便捷的工作环境,同时帮助企业更好地管理远程工作流程。项目包含了完整的数据库设计、前后端代码实现以及详细的文档说明,非常适合计算机相关专业的毕设学生和需要进行项目实战练习的Java学习者。 系统的核心功能包括用户管理、任务分配、进度跟踪、文件共享和在线沟通等。用户管理模块允许管理员创建和管理用户账户,分配不同的权限。任务分配模块使项目经理能够轻松地分配任务给团队成员,并设置截止日期。进度跟踪模块允许员工实时更新他们的工作状态,确保项目按计划进行。文件共享模块提供了一个安全的平台,让团队成员可以共享和协作处理文档。在线沟通模块则支持即时消息和视频会议,以增强团队之间的沟通效率。 技术栈方面,后端采用了Spring框架来管理业务逻辑,SpringMVC用于构建Web应用程序,MyBatis作为ORM框架简化数据库操作。前端则使用Vue.js来实现动态用户界面,搭配Vue Router进行页面导航,以及Vuex进行状态管理。数据库选用MySQL,确保数据的安全性和可靠性。 该项目不仅提供了一个完整的技术实现示例,还为开发者留下了扩展和改进的空间,可以根据实际需求添加新功能或优化现有功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值