题解 洛谷 P2612 【[ZJOI2012]波浪】DP+高精
题目描述
分析
因为有绝对值不好处理,所以我们强制从小到大填数
设 \(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+高精的更多相关文章
- 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】
题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...
- [CEOI2007]树的匹配Treasury(树形DP+高精)
题意 给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配. N≤1000,其中40%的数据答案不超过 108 题解 显然的树形DP+高精. 这题是作为考试题考 ...
- 洛谷1387 二维dp 不是特别简略的题解 智商题
洛谷1387 dp题目,刚开始写的时候使用了前缀和加搜索,复杂度大概在O(n ^ 3)级别,感觉这么写还是比较对得起普及/提高-的难度的..后来看了题解区各位大神的题解,开始一脸mb,之后备受启发. ...
- NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...
- [洛谷P2597] [ZJOI2012]灾难
洛谷题目链接:[ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引 ...
- [洛谷P2610] [ZJOI2012]旅游
洛谷题目链接:[ZJOI2012]旅游 题目描述 到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~ 经过一番抉择,两人决定将T国作为他们的目的地.T国的国土可以用一个 ...
- 题解 洛谷P5018【对称二叉树】(noip2018T4)
\(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...
- 题解 洛谷 P3396 【哈希冲突】(根号分治)
根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...
- 题解-洛谷P4229 某位歌姬的故事
题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...
随机推荐
- 【新阁教育】S7.NET+Log4Net+SQLSugar+MySQL搭建Iot平台
1.搭建西门子S7仿真环境 新阁教育提醒您基于PLCSIM-Advanced搭建西门子S7仿真环境注意事项: 1.通过dotNet工控上位机公众号后台发送PLCSIM-Advanced获取软件 2.安 ...
- pandas模块常用函数解析之Series(详解)
pandas模块常用函数解析之Series 关注公众号"轻松学编程"了解更多. 以下命令都是在浏览器中输入. cmd命令窗口输入:jupyter notebook 打开浏览器输入网 ...
- Django项目-个人网站之事项模块
Django项目之个人网站 关注公众号"轻松学编程"了解更多. Github地址:https://github.com/liangdongchang/MyWeb.git 感兴趣的可 ...
- Django之富文本(获取内容,设置内容)
富文本 1.Rich Text Format(RTF) 微软开发的跨平台文档格式,大多数的文字处理软件都能读取和保存RTF文档,其实就是可以添加样式的文档,和HTML有很多相似的地方 图示 2.tin ...
- .netcore3.1使用log4net/nlog记录日志
.netcore3.1使用log4net/nlog记录日志 .netcore3.1与2.x之间很是有不少差异的.本来想通过ctrl+c,ctrl+v将在2.2中实现的简单日志记录搬到.netcore3 ...
- CF1271E Common Number
数学+二分 连续打了3场$codeforces$,深深的被各种模拟贪心分类讨论的$C$,$D$题给恶心到了 还有永远看到题一脸懵的$B$题 首先考虑画出不同函数值迭代转移的关系,要注意考虑连边是否能成 ...
- 25个Android酷炫开源UI框架
1.Side-Menu.Android 分类侧滑菜单,Yalantis 出品.项目地址:https://github.com/Yalantis/Side-Menu.Android2.Context-M ...
- asp.net利用SmtpClient发送邮件
using System; using System.Data; using System.Web.UI; using System.Data.OracleClient; using DBUtilit ...
- php 正则金额验证
$money_reg = '/^[1-9]\d*|^[1-9]\d*.\d+[1-9]$/';if(!preg_match($money_reg, $money)){ $this->ajaxEr ...
- 使用IDEA推送项目至gitee平台或github平台
IDEA项目推送至gitee平台或github平台 1.首先在gitee平台上创建项目 在gitee平台上创建仓库应该很简单,依据下图所示填写相应信息,即可完成创建. 需要说明的一点是,现在java开 ...