试题来源

清华大学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. LVS入门篇(四)之LVS实战

    一.LVS的NAT模式实战 1.环境说明: HOST OS role remask 192.168.56.12 Centos 7.4 LVS调度器(1.2.7) VIP:192.168.0.104 1 ...

  2. [css 实践篇]CSS中的尺寸单位

    绝对单位 px: Pixel 像素 pt: Points 磅 pc: Picas 派卡 in: Inches 英寸 mm: Millimeter 毫米 cm: Centimeter 厘米 q: Qua ...

  3. C#随堂

    顺序语句 上到下执行 分支语句 if    else switch() { case 1: Console.WriteLine(1); break; case 2: Console.WriteLine ...

  4. 搜索引擎Solr6.2.1 索引富文本(word/pdf/txt/html)

    一:首先建立Core 在core下面新建lib文件夹,存放相关的jar包,如图所示: lib文件夹打开所示,这些类库在solr6.2.1解压之后都能找到: 修改solrconfig.xml,把刚刚建的 ...

  5. Eclipse与MySQL数据库连接步骤

    将Eclipse与数据库进行连接的步骤: 1. 下载并配置MySQL 2. 为新建的项目配置mysql的jar包(jdbc和connection的配置) a) 可直接引用外部文件(不建议做,这样项目一 ...

  6. mongodb windows 4 zip安装

    安装mongoDB目的:学习Express,顺带mongodb. 本文目的: 4.0.2的mongodb在windows7上竟然安装不了. 没办法,用压缩包手动安装吧... 安装环境:win7sp1x ...

  7. 程序员必备神器--vps主机

    今天推荐一个功能强大.居家必备的神器给刚入行或还不了解它的同学们.且不说它有什么功能,它有多好用,先说先你有没有碰到过这些问题吧. 用百度查技术问题,发现都是互相抄袭和广告,大佬都说google好,但 ...

  8. JAVA学习笔记--数组初始化

    JAVA中,数组只是相同类型的.用一个标识符名称封装到一起的一个对象序列或基本类型数据序列.数组通过方括号下标操作符[]来定义和使用,要定义一个数组只需在类型名后面加上一个方括号即可,如: int[] ...

  9. 《Learning scikit-learn Machine Learning in Python》chapter1

    前言 由于实验原因,准备入坑 python 机器学习,而 python 机器学习常用的包就是 scikit-learn ,准备先了解一下这个工具.在这里搜了有 scikit-learn 关键字的书,找 ...

  10. sprint3最终演示及团队贡献分

    团队名:在考虑 团队项目:复利计算 项目演示: 之前的功能都有演示过就不再一一截图,把我们新增加的功能说一下 首先用户进入我们的网页可以登录或者注册,注册的用户可以直接输入用户名及密码登录,没有注册的 ...