题目描述

题目传送门

分析

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

设 \(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. mysql分组函数与查询

    Ⅰ.分组函数的分类: max():最大值 min():最小值 sum():和 avg():平均值 count():计算非空的个数 这些都是通用的,sqlserver.oracle.mysql都是一样的 ...

  2. DP百题练(一)

    目录 DP百题练(一) 线性 DP 简述 Arithmetic Progressions [ZJOI2006]物流运输 LG1095 守望者的逃离 LG1103 书本整理 CH5102 移动服务 LG ...

  3. Codeforces Round #677 (Div. 3) 题解

    Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...

  4. Kafka_2.12-2.5.1集群搭建与参数调优

    Kafka是目前业界使用最广泛的消息队列.数据流转常见这样的业务场景,客户端把采集到的日志推送给Kafka,业务方可以消费Kafka的数据落地HDFS,用于离线分析,也可以使用Spark或Flink消 ...

  5. 2、CPU详解

    一.五大组成单元 => 三大核心组件 组成计算机五大单元可以合并成三大核心组件:CPU.IO设备.主存储器 1.控制单元+算数逻辑单元 => CPU 2.主存储器,即主记忆体 3.输入单元 ...

  6. leetcode111:combination-sum

    题目描述 给出一组候选数C和一个目标数T,找出候选数中加起来和等于T的所有组合. C中的数字在组合中可以被无限次使用 注意: 题目中所有的数字(包括目标数T)都是正整数 你给出的组合中的数字 (a 1 ...

  7. 经典c程序100例==11--20

    [程序11] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月 后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔子的规律为数列1 ...

  8. CSS实现模拟百度分享侧边栏效果

    在<JS模拟百度分享侧边栏效果>一文中对于Div区块的运动通过JS实现了鼠标移入滑出显示,鼠标移出滑入隐藏的效果.其实在CSS3中通过transition属性就可以较为轻松实现. < ...

  9. 《.NET 5.0 背锅案》第3集-剧情反转:EnyimMemcachedCore 无罪,.NET 5.0 继续背锅

    今天晚上基于第2集中改进版的 EnyimMemcachedCore 进行了发布,发布过程中故障重现,最大的嫌犯 EnyimMemcachedCore 被证明无罪,暂时委屈 .NET 5.0 继续背锅. ...

  10. HiveMQ TDengine extension 使用指南

    我们简单介绍一下 HiveMQ extension for TDengine 的部署和使用方法. TDengine 和 HiveMQ 部署方法 TDengine 安装最新 TDengine serve ...