试题来源

清华大学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. Nginx入门篇(五)之LNMP环境应用

    一.LNMP组合工作原理 (1)用户通过浏览器输入域名请求Nginx web服务: (2)Nginx对请求的资源进行判断,如果是静态资源,则由Nginx返回给用户:如果是动态请求(.php文件),那么 ...

  2. Drupal7 配置多站点及为每个站点设置语言

    默认情况 在Drupal7的安装目录下存在sites目录 sites目录结构如下: --all --default --example.sites.php --README.txt 1. 添加新域名, ...

  3. 洛谷 P1941 飞扬的小鸟

    洛谷 P1941 飞扬的小鸟 原题链接 首先吐槽几句 noip都快到了,我还不刷起联赛大水题! 题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节 ...

  4. Hibernate5使用注解方式(转)

    用Hibernate5使用映射文件时存在一个问题没有解决,在映射文件中配置了student_sequence,但找不到映射文件自增长的序列的sequence(Oracle)数据库. 输出的是 Hibe ...

  5. Scrapy爬取美女图片续集 (原创)

    上一篇咱们讲解了Scrapy的工作机制和如何使用Scrapy爬取美女图片,而今天接着讲解Scrapy爬取美女图片,不过采取了不同的方式和代码实现,对Scrapy的功能进行更深入的运用.(我的新书< ...

  6. C#之Ref,Out以及TryParse()的用法

    ref和out用法很简单,我记下来也提醒自己要用更好的方式去写代码,不要让代码过于臃肿,让人看得头痛.直接写 ref:ref关键字就是让参数进行传递,但是需要初始化,而out不需要初始化参数 ref用 ...

  7. 我们一起学习WCF 第三篇头消息验证用户身份

    前言:今天我主要写的是关于头消息的一个用处验证用户信息 下面我画一个图,可以先看图 第一步:我们先开始做用户请求代码 首先:创建一个可执行的上下文对象块并定义内部传输的通道 using (Operat ...

  8. ----------BMI指数小程序----------

    # 1.创建并输出菜单, 菜单是不可变的. 所以使用元组# menus = ("1, 录入", "2, 查询", "3, 删除", &quo ...

  9. mfs分布式系统从理论简介到实战部署

    文章前面想说的话:这篇博客写出来真是有点累到了,本来昨天就基本就写好了,放在草稿里面,今天打开就没有了!!唉,就尼玛离我而去了,只有重写,然后中间虚拟机还“爆炸”重启又搞了一会,不容易呀!!希望各位博 ...

  10. Unity Lighting - Light Probes 光照探针(十)

      Light Probes 光照探针 Only static objects are considered by Unity’s Baked or Precomputed Realtime GI s ...