题解 洛谷 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)\) 表示 \( ...
随机推荐
- STM32入门系列-STM32外设地址映射
片上外设区分为四条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1挂载低速外设,APB2和AHB挂载高速外设.相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外 ...
- JavaSE基础语法学习-异常
异常 异常指程序运行中出现的不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等. 异常发生在程序运行期间,它影响了正常的程序执行流程. 比如说,你的代码少了一个分号,那么运行出来结果是提示是 ...
- C的输入&输出
格式说明符 输出 %d整型输出,%ld长整型输出, %o以八进制数形式输出整数, %x以十六进制数形式输出整数,或输出字符串的地址. %u以十进制数输出unsigned型数据(无符号数).注意:%d与 ...
- 【转】jps 命令使用
jps(Java Virtual Machine Process Status Tool)是JDK1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简 ...
- ip_rcv 中使用skb_share_check
/* * Main IP Receive routine. */ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct pack ...
- TCP特点
1.基于字节流:面向连接:可靠传输:缓冲传输:全双工:流量控制.TCP如何保证可靠性:差错:校验和丢包:超时重传+确认失序:seq(序号)重复:seq(序号)1.数据被分割成TCP认为最合适发送的数据 ...
- Innodb之线程独享内存
引用链接: https://blog.csdn.net/miyatang/article/details/54881547 https://blog.csdn.net/wyzxg/article/de ...
- Innodb之全局共享内存
参考链接: https://blog.csdn.net/miyatang/article/details/54881547 https://blog.csdn.net/wyzxg/article/de ...
- appium 常用方法总结
1.appium启动任意的Activity 在手机上启动任意的Activty用driver.start_activity方法,如果启动的Activity不是测试应用程序的一部分,它也将启动该活动的应用 ...
- webug第十三关:XSS
第十三关:XSS 点击链接 xss,弹框框