试题来源

清华大学2011年百名信息学优秀高中学子夏令营

问题描述

有人打算送给你一条宝石项链,包含了N颗五颜六色(一共有M种颜色)的宝石。因为本问题中你只关心每个宝石的颜色,而且项链现在两头还没有接在一起,它可以被看成是一个数字串。

你希望在五颜六色的宝石中看到连续的一段同色宝石。因此,你定义一根宝石项链的幸运度是它最长的由同色宝石构成的连续子串的长度。 比如,项链112322211的幸运度是3,因为它包括了由同色宝石构成的子串222。而首尾的两个11并不构成连续1111,因为这个项链现在是串形的而不是环形的。

然而,你还没有见到这个项链。你只知道每个宝石是每种颜色的概率。并且,已知每个宝石的颜色分布是独立的。现在你希望在真的见到这条项链之前计算一下,这条项链的幸运度的期望是多少?

输入格式

输入的第一行有两个正整数N和M。

后面N行每行有M个非负实数。其中第i行第j列的数P_(i,j)含义是第i个宝石是颜色j的概率是P_(i,j)。每行的M个实数保证和为1。

输出格式

一个实数,即这条项链的幸运度的期望。四舍五入至小数点后6位。

样例输入

4 2

1.0 0.0

0.5 0.5

0.0 1.0

0.5 0.5

样例输出

2.250000

样例说明

我们用1和2来分别表示两种颜色的宝石,则这串项链有四种等概率的情形:1121,1122,1221和1222。它们的幸运度分别是2,2,2,3,因此期望的幸运度是2.25。

数据规模和约定

30%的数据满足N≤16,M≤3。

60%的数据满足N≤100。

100%的数据满足2≤N≤1000,2≤M≤10。

题解

首先,先想到60分的dp,设 \(f[i][j][k][t]\) 代表到第 \(i\) 位,最长连续段长为 \(j\) ,末尾连续段长为 \(k\) ,末尾一位颜色为 \(t\) 的概率,然后暴力转移

这是60分程序:

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100+10,MAXM=10+10;
int n,m;
db ans,f[MAXN][MAXN][MAXN][MAXM],P[MAXN][MAXM];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
read(n);read(m);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)scanf("%lf",&P[i][j]);
for(register int i=1;i<=m;++i)f[0][0][0][i]=1.0;
for(register int i=0;i<n;++i)
for(register int j=0;j<=i;++j)
for(register int k=0;k<=j;++k)
for(register int t=1;t<=m;++t)
{
if(k<j)f[i+1][j][k+1][t]+=f[i][j][k][t]*P[i+1][t];
else f[i+1][j+1][k+1][t]+=f[i][j][k][t]*P[i+1][t];
for(register int p=1;p<=m;++p)
if(t==p)continue;
else f[i+1][j][1][p]+=f[i][j][k][t]*P[i+1][p];
}
for(register int i=1;i<=n;++i)
for(register int j=1;j<=i;++j)
for(register int k=1;k<=m;++k)ans+=f[n][i][j][k]*i;
printf("%.6f\n",ans);
return 0;
}

然后,压一维,不计某位连续段长,而在转移的时候把新的连续段长超过 \(j\) 的概率减去,保证已经考虑的位置中的连续段一定不大于 \(j\)

设 \(f[i][j][k]\) 表示到第 \(i\) 位,连续段长不超过 \(j\) ,末尾颜色为 \(k\) 的概率,\(g[i][j][k]\) 表示从第 \(i\) 位到第 \(j\) 位,期间颜色全部是 \(k\) 的概率,\(s[i][j]\) 为到第 \(i\) 位,连续段长不超过 \(j\)的概率

那么

\(s[i][j]=\sum_{k=1}^mf[i][j][k]\) ,这个很好理解

\(f[i][j][k]=s[i-1][j]*g[i][i][k]-(s[i-j-1][j]-f[i-j-1][j][k])*g[i-j][i][k]\)

这个东西有点杂

首先如果不去保证连续段长度一定不大于 \(j\) ,概率就是 \(s[i-1][j]*g[i][i][j]\) ,这个东西肯定是要减去不合法情况的,唯一的不合法情况就是加了这个新的数,使得末尾的连续段长度变成了 \(j+1\) ,也就是 \(i-j\) 到 \(i\) 期间全部都是 \(k\) 颜色。所以就是后面减去的东西。\(s[i-j-1][j]\) 减去 \(f[i-j-1][j][k]\) 是因为要保证 \(i-j-1\) 位上不能是 \(k\) 颜色,因为如果是 \(k\) 颜色,那么末尾连续段的长度就不止 \(j+1\) 了,这样的情况在之前转移的时候已经减过了

AC程序:

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=1000+10,MAXM=10+10;
int n,m;
db ans,f[MAXN][MAXN][MAXM],P[MAXN][MAXM],g[MAXN][MAXN][MAXM],s[MAXN][MAXN];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
read(n);read(m);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)scanf("%lf",&P[i][j]);
for(register int k=1;k<=m;++k)
for(register int i=1;i<=n;++i)
{
g[i][i][k]=P[i][k];
for(register int j=i+1;j<=n;++j)g[i][j][k]=g[i][j-1][k]*P[j][k];
}
for(register int i=1;i<=n;++i)s[0][i]=1;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
for(register int k=1;k<=m;++k)
{
f[i][j][k]=s[i-1][j]*g[i][i][k];
if(i-j-1>=0)f[i][j][k]-=(s[i-j-1][j]-f[i-j-1][j][k])*g[i-j][i][k];
s[i][j]+=f[i][j][k];
}
for(register int i=1;i<=n;++i)ans+=(s[n][i]-s[n][i-1])*i;
printf("%.6f\n",ans);
return 0;
}

【刷题】清橙 A1295 necklace的更多相关文章

  1. 清橙A1206.小Z的袜子 && CF 86D(莫队两题)

    清橙A1206.小Z的袜子 && CF 86D(莫队两题) 在网上看了一些别人写的关于莫队算法的介绍,我认为,莫队与其说是一种算法,不如说是一种思想,他通过先分块再排序来优化离线查询问 ...

  2. BZOJ4590 自动刷题机

    Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写 ...

  3. 教你用python写:HDU刷题神器

    声明:本文以学习为目的,请不要影响他人正常判题 HDU刷题神器,早已被前辈们做出来了,不过没有见过用python写的.大一的时候见识了学长写这个,当时还是一脸懵逼,只知道这玩意儿好屌-.时隔一年,决定 ...

  4. 清橙A1212:剪枝

    题面 清橙 Sol 一种新的树上\(DP\)姿势 从左往右按链\(DP\) 做法: 维护两个栈\(S1\),\(S2\) \(S1\)存当前的链 \(S2\)存分叉点以下要改的链 \(Dfs\),弄一 ...

  5. 清橙A1202&Bzoj2201:彩色圆环

    因为Bzoj是权限题,所以可以去清橙做一下 Sol 突然考了一道这样的题,考场上强行\(yy\)出来了 win下评测Long double爆零TAT 首先肯定是破环为链变成序列问题辣 那么就要求第一个 ...

  6. LeetCode刷题专栏第一篇--思维导图&时间安排

    昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...

  7. [清橙A1210]光棱坦克

    [清橙A1210]光棱坦克 题目大意: 平面上放置了\(n(n\le7000)\)个反射装置,光纤将从某个装置出发,在经过一处装置时发生反射,若经过的装置坐标依次为\((x_1,y_1),(x_2,y ...

  8. JS、JAVA刷题和C刷题的一个很重要的区别

    就是最近在做树方面的题时,发现JS和JAVA刷题和C刷题的一个很重要的区别就是传入null的区别 当遍历的时候,C传参数时可以传进去null的指针,因为递归进去,出来时,指针还是指着那个地方 但是JS ...

  9. lintcode 刷题 by python 总结(1)

    博主之前在学习 python 的数据结构与算法的基础知识,用的是<problem-solving-with-algorithms-and-data-structure-using-python& ...

随机推荐

  1. springboot对security的后端配置

    一.Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring ...

  2. Linux安装gitlab

    一.GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务.安装方法是参考GitLab在GitHub上的Wiki页面. 二.我相信使用过git的开 ...

  3. MSP430的CAN通信发送

    1. 电路图如下,RE是接收使能,DE是发送使能,看图的话,这个CAN只支持半双工 2. 使用MSP430F149,以下代码只有发送,其实用的是串口 #include <msp430x14x.h ...

  4. PHP反序列化漏洞代码审计—学习资料

    1.什么是序列化 A.PHP网站的定义: 所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示.unserialize()函数能够重新把字符串变回php原来的值. ...

  5. Selenium2+python自动化-iframe

    前言 本篇详细讲解iframe的相关切换操作. 一.frame和iframe区别 Frame与Iframe两者可以实现的功能基本相同,不过Iframe比Frame具有更多的灵活性. frame是整个页 ...

  6. 【UGUI】 (二)--------- 小地图

    在绝大多数游戏中,小地图都是极为常见的一个模块而且十分重要.在Unity里面如何制作一个地图其实也是比较简单的 一. 创建玩家与敌人 创建一个Capsule,命名为Player,代表我们的游戏玩家,创 ...

  7. 亚马逊CEO贝索斯致股东信:阐述公司未来计划

    亚马逊CEO 杰夫·贝索斯(Jeff Bezos)今天发布年度股东信, 详细描述了亚马逊的产品.服务和未来计划,当然,信中并没有任何的硬数据,比如说亚马逊Kindle的销量等等.但这封信也包括一些颇令 ...

  8. sqoop导入数据到hive表中的相关操作

    1.使用sqoop创建表并且指定对应的hive表中的字段的数据类型,同时指定该表的分区字段名称 sqoop create-hive-table --connect "jdbc:oracle: ...

  9. springboot 集成 swagger

    1. 首先配置swaggerConfigpackage com.lixcx.lismservice.config; import com.lixcx.lismservice.format.Custom ...

  10. win10 tomcat不能访问问题

    问题描述:电脑是Win10系统的,安装了Tomcat后,本机通过80端口能顺利访问.但局域网内的其他机器却无法访问这台电脑的Tomcat服务. 故障分析: 将防火墙关闭后,可以访问,所以问题就出在防火 ...