题目描述

题目传送门

分析

因为有绝对值不好处理,所以我们强制从小到大填数

设 \(f[i][j][p][o]\) 为当前填到了第 \(i\) 个数,波动强度为 \(j\),有 \(p\) 个连续段并且两端的端点选了 \(o\) 个时的概率

注意这里的连续段是强制规定的

那么转移有五种:

\(1\)、填的数单独成为一段并且不在整个区间的两个端点上

\(f[i+1][j-i*2-2][p+1][o]+=f[i][j][p][o]*(p+1-o)\)

因为后面填在这个数两边的数一定比这个数大,所以这个数一定做负贡献

之前一共有 \(p\) 段,可以填的位置有 \(p+1\) 种

因为一个段如果在整个区间的两端的话,只能在它的一边填,还要减去 \(o\)

\(2\)、填的数单独成为一段并且在整个区间的两个端点上

\(f[i+1][j-i-1][p+1][o+1]+=f[i][j][p][o]*(2-o)\)

此时这个数只会做一次负贡献

方案数为剩余的整个区间的端点的数量,即 \(2-o\)

\(3\)、新填的数放在已有的连续段的一端并且不与其它连续段相邻

\(f[i+j][j][p][o]+=f[i][j][p][o]*(p*2-o)\)

因为这个数一定做一次正贡献和一次负贡献,所以会抵消,总贡献不变

每个连续段都有两个端点可以选,再减去已选整个区间的端点的数量

\(4\)、新填的数放在已有的连续段的一端并且与其它连续段相邻

\(f[i+1][j+2*i+2][p-1][o]+=f[i][j][p][o]*(p-1)\)

其实就是把两个端拼成了一个大段

做两次正贡献

\(5\)、新填的数放在已有的连续段的一端并且当前的数填到了整个区间的端点上

\(f[i+1][j+i+1][p][o+1]+=f[i][j][p][o]*(2-o)\)

做一次正贡献

因为题目要求保留的位数不一样

所以,对于精度较低的测试点,可以用 \(double\) 写

对于精度较高的测试点,我们可以手写高精度

手写高精度浮点数其实就是先把整个数左移很多位

然后进行正常的加、乘、除的操作

最后要多少位再四舍五入取到多少位即可

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#define rg register
const int maxn=105,maxm=8005,bas=2500,jz=10000000;
int n,m,k,mmax;
struct asd{
int num[10],len;
asd(){
memset(num,0,sizeof(num));
len=0;
}
friend asd operator +(const asd &A,const asd &B){
asd C;
C.len=std::max(A.len,B.len);
for(rg int i=0;i<C.len;i++){
C.num[i]+=A.num[i]+B.num[i];
if(C.num[i]>=jz){
C.num[i]-=jz;
C.num[i+1]+=1;
}
}
if(C.num[C.len]) C.len++;
return C;
}
friend asd operator *(const asd &A,const asd &B){
asd C;
for(rg int i=0;i<B.len;i++){
for(rg int j=0;j<A.len;j++){
C.num[i+j]+=B.num[i]*A.num[j];
}
}
for(rg int i=0;i<B.len;i++){
for(rg int j=0;j<A.len;j++){
if(C.num[i+j]>=jz){
C.num[i+j+1]+=C.num[i+j]/jz;
C.num[i+j]%=jz;
}
}
}
C.len=B.len+A.len;
while(C.num[C.len-1]==0 && C.len-1!=0) C.len--;
return C;
}
friend asd operator /(const asd &A,const int B){
asd C,D;
D=A;
for(rg int i=D.len-1;i>=0;i--){
rg int haha=D.num[i]+D.num[i+1]*jz;
C.num[i]=haha/B;
D.num[i]=haha%B;
D.num[i+1]=0;
if(i==0 && D.num[i]>=B/2){
C.num[i]++;
}
if(C.len==0 && C.num[i]){
C.len=i+1;
}
}
while(C.num[C.len-1]==0 && C.len-1!=0) C.len--;
return C;
}
void read(int aa){
len=0;
while(aa){
num[len++]=aa%jz;
aa/=jz;
}
while(num[len-1]==0 && len-1!=0) len--;
}
void write(int aa){
rg int pd=0;
printf("0.");
for(rg int i=len-1;i>=0;i--){
if(aa-7>=0){
if(aa==7 && num[i-1]%1000000%10>=5) pd=1;
printf("%07d",num[i]+pd);
aa-=7;
} else {
if(aa==1 && num[i]/100000%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/1000000%10+pd);
aa--;
}
if(aa==1 && num[i]/10000%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/100000%10+pd);
aa--;
}
if(aa==1 && num[i]/1000%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/10000%10+pd);
aa--;
}
if(aa==1 && num[i]/100%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/1000%10+pd);
aa--;
}
if(aa==1 && num[i]/10%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/100%10+pd);
aa--;
}
if(aa==1 && num[i]%10>=5){
pd=1;
}
if(aa){
printf("%01d",num[i]/10%10+pd);
aa--;
}
if(aa){
printf("%01d",num[i]%10+pd);
aa--;
}
break;
}
}
printf("\n");
}
}g[2][maxm][maxn/2][3];
asd anss;
void solve1(){
mmax=n/2+1;
rg int now=1;
g[0][bas][0][0].num[6]=1;
g[0][bas][0][0].len=7;
for(rg int i=0;i<n;i++){
now^=1;
for(rg int j=0;j<maxm;j++){
for(rg int p=0;p<=mmax;p++){
for(rg int o=0;o<=2;o++){
g[now^1][j][p][o].len=0;
memset(g[now^1][j][p][o].num,0,sizeof(g[now^1][j][p][i].num));
}
}
}
asd haha;
for(rg int j=0;j<maxm;j++){
for(rg int p=0;p<=mmax;p++){
for(rg int o=0;o<=2;o++){
if(g[now][j][p][o].len){
if(j-2*i-2>=0){
haha.read(p+1-o);
g[now^1][j-2*i-2][p+1][o]=g[now^1][j-2*i-2][p+1][o]+g[now][j][p][o]*haha/(i+1);
}
if(o<2 && j-i-1>=0){
haha.read(2-o);
g[now^1][j-i-1][p+1][o+1]=g[now^1][j-i-1][p+1][o+1]+g[now][j][p][o]*haha/(i+1);
}
haha.read(p*2-o);
g[now^1][j][p][o]=g[now^1][j][p][o]+g[now][j][p][o]*haha/(i+1);
if(p && j+2*i+2<maxm){
haha.read(p-1);
g[now^1][j+2*i+2][p-1][o]=g[now^1][j+2*i+2][p-1][o]+g[now][j][p][o]*haha/(i+1);
}
if(o<2 && j+i+1<maxm){
haha.read(2-o);
g[now^1][j+i+1][p][o+1]=g[now^1][j+i+1][p][o+1]+g[now][j][p][o]*haha/(i+1);
}
}
}
}
}
}
for(rg int j=bas+m;j<=bas+(n+1)*n/2;j++){
anss=anss+g[now^1][j][1][2];
}
anss.write(k);
}
double f[2][maxm][maxn/2][3],ans;
void solve2(){
mmax=n/2+1;
rg int now=1;
f[0][bas][0][0]=1.0;
for(rg int i=0;i<n;i++){
now^=1;
for(rg int j=0;j<maxm;j++){
for(rg int p=0;p<=mmax;p++){
for(rg int o=0;o<=2;o++){
f[now^1][j][p][o]=0;
}
}
}
for(rg int j=0;j<maxm;j++){
for(rg int p=0;p<=mmax;p++){
for(rg int o=0;o<=2;o++){
if(f[now][j][p][o]){
if(j-2*i-2>=0) f[now^1][j-2*i-2][p+1][o]+=f[now][j][p][o]*(p+1-o)/(i+1);
if(o<2 && j-i-1>=0) f[now^1][j-i-1][p+1][o+1]+=f[now][j][p][o]*(2-o)/(i+1);
f[now^1][j][p][o]+=f[now][j][p][o]*(p*2-o)/(i+1);
if(p && j+2*i+2<maxm) f[now^1][j+2*i+2][p-1][o]+=f[now][j][p][o]*(p-1)/(i+1);
if(o<2 && j+i+1<maxm) f[now^1][j+i+1][p][o+1]+=f[now][j][p][o]*(2-o)/(i+1);
}
}
}
}
}
for(rg int j=bas+m;j<=bas+(n+1)*n/2;j++){
ans+=f[now^1][j][1][2];
}
std::cout<<std::fixed<<std::setprecision(k)<<ans<<std::endl;
}
int main(){
std::cin>>n>>m>>k;
if(k<=8) solve2();
else solve1();
return 0;
}

题解 洛谷 P2612 【[ZJOI2012]波浪】DP+高精的更多相关文章

  1. 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】

    题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...

  2. [CEOI2007]树的匹配Treasury(树形DP+高精)

    题意 给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配. N≤1000,其中40%的数据答案不超过 108 题解 显然的树形DP+高精. 这题是作为考试题考 ...

  3. 洛谷1387 二维dp 不是特别简略的题解 智商题

    洛谷1387 dp题目,刚开始写的时候使用了前缀和加搜索,复杂度大概在O(n ^ 3)级别,感觉这么写还是比较对得起普及/提高-的难度的..后来看了题解区各位大神的题解,开始一脸mb,之后备受启发. ...

  4. NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...

  5. [洛谷P2597] [ZJOI2012]灾难

    洛谷题目链接:[ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引 ...

  6. [洛谷P2610] [ZJOI2012]旅游

    洛谷题目链接:[ZJOI2012]旅游 题目描述 到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~ 经过一番抉择,两人决定将T国作为他们的目的地.T国的国土可以用一个 ...

  7. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  8. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  9. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

随机推荐

  1. Gerrit 服务搭建和升级详解(包括 H2 数据库迁移 MySQL 步骤)

    1. 安装Gerrit-2.9.5版本(Ubuntu) Gerrit版本:Gerrit-2.9.5.war 操作系统:Ubuntu 16.04.3 JAVA环境:java version " ...

  2. Socket创建简单服务器和客户端程序

    使用Socket编程创建简单服务器和客户端 要知道的 Socket-AddressFamily, SocketType, ProtocolType https://blog.csdn.net/weix ...

  3. 跟我一起学Redis之Redis事务简单了解一下

    前言 关系数据库中的事务,小伙伴们应该是不陌生了,不管是在开发还是在面试过程中,总有两个问题逃不掉: 说说事务的特性: 事务隔离级别是怎么一回事? 事务处理不好,数据就可能不准确,最终就会导致业务出问 ...

  4. win10,安装 vmware 后没有虚拟网卡,导致虚拟机没有 ip

    1.确认关闭windows firewall 服务,最保险的关闭时先把服务改为手动再关闭防止塔自动启动! 2.确认开启Device  Install Service .Device Setup Ser ...

  5. 查看ceph集群被哪些客户端连接

    前言 我们在使用集群的时候,一般来说比较关注的是后台的集群的状态,但是在做一些更人性化的管理功能的时候,就需要考虑到更多的细节 本篇就是其中的一个点,查询ceph被哪些客户端连接了 实践 从接口上来说 ...

  6. 编译的Ceph二进制文件过大问题

    前言 在ceph的研发群里看到一个cepher提出一个问题,编译的ceph的二进制文件过大,因为我一直用的打包好的rpm包,没有关注这个问题,重新编译了一遍发现确实有这个问题 本篇就是记录如何解决这个 ...

  7. 利用HUtool读取Excel内容

    // 1.获取上传文件输入流 InputStream inputStream = null; try{ inputStream = file.getInputStream(); }catch (Exc ...

  8. eclipse 和 myeclipse 字符编码设置

    需要设置的几处地方为: Window->Preferences->General ->Content Type 所有 Default encoding 设置为UTF-8 Window ...

  9. 【Redis】利用 Redis 实现分布式锁

    技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...

  10. RestPack Java实现Html转PDF文件

    最近公司需要将前端一个图表统计导出为pdf.前端导出显示的pdf还是可以的,但是将会导致页面不可用与卡死状态.所以由后端寻找解决方案. 以下为解决方案调研 https://www.cnblogs.co ...