hdu 4576(简单概率dp | 矩阵优化)
艰难的一道题,体现出菜菜的我。。。
首先,先吐槽下。 这题到底出题人是怎么想的,用普通概率dp水过??? 那为什么我概率dp写的稍微烂点就一直tle? 感觉很不公平。大家算法都一致,因为我程序没有那么简练就过不了。 太坑了。。。
当然,说到底还是实力的问题,谁叫你不会一些常数级别的优化。 谁叫你写的时候不写的好一点。
比赛的时候在速度秒掉了最后两题后,卡这道题卡了4个多小时,也没有心情去看其他的题目了。 期间想了各种优化的方法。 最后因为一个小错误wa了N次后没有过而遗憾终身。。。
1. 直接 概率dp ,时间可能会很长,因为循环的次数达到了10^8次方,所以循环最内部的运算必须不能过多。 如果剩去%(这个比较费时的,话说至少是+,-的5、6倍吧)还有输入用自己定义的函数(就是不用scanf,用getchar()一个一个的读入)可以将时间缩到<2000ms
附一份普通的3000+ms的
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std; double dp[][]; int main()
{
//freopen("//home//chen//Desktop//ACM//in.text","r",stdin);
int n,m,l,r;
while(scanf("%d%d%d%d",&n,&m,&l,&r)&&(n+m+l+r))
{
int a=,b=;
memset(dp,,sizeof(dp));
dp[a][]=;
for(int i=;i<m;i++)
{
int tmp;
scanf("%d",&tmp);
tmp%=n;
for(int j=;j<=n;j++)
{
dp[b][j]=dp[a][(j+tmp-)%n+]*0.5+dp[a][(j-tmp+n-)%n+]*0.5;
}
swap(a,b);
}
double ans=;
for(int i=l;i<=r;i++)
ans+=dp[a][i];
printf("%.4lf\n",ans);
}
return ;
}
2. 可以用矩阵优化。
首先可以知道的是这个m次运算是满足结合律的。 于是快速幂的思想就可以运用了。
统计出m次运算中 移k(1<= k <=200)位的个数。 然后这些移相同位的运算都是相同的,可以用快速幂使复杂度变成log,也就是将m次运算变成 约等于logm
构造一个矩阵,发现如果直接用矩阵乘法的话,一次相乘复杂度就达到了n*n*n也就是8*10^6 。
但是因为这题的特殊性,构造出来的矩阵对于每一列仅有的两个元素都恰好是等差错开排列的。
a b 0 a b 0 a*a 2ab b*b
0 a b * 0 a b = b*b a*a 2ab
b 0 a b 0 a 2ab b*b a*a
这里a=b=0.5 ,(还有可能a,b在同一个位置,这时只有一个a=1). 而且值得注意的时候一般有规律的矩阵乘出来的结果一般也是有规律的。
这样就可以只求出第一行的结果,然后剩余的用第一行的结果推就行了。这样复杂度就为n*n
总的复杂度是n*n*k*logm。 理论上可以接受,而且应该没有这么大,因为不可能每次进行快速幂的复杂度都达到logm。
以上有一部分引用,代码也在其中 http://www.cnblogs.com/kiwi-bird/archive/2013/08/10/3250696.html
时间大概1700+ms
3. 我自己想出来的一种类似于矩阵快速幂的方法,至少思想是这样的。 时间1400+ms
算法原理,思想都类似于快速幂,当时感觉也不是特别好就不详细解释了。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std; int n,m,l,r;
int save[];
double g[];
double tmp[];
double sum[]; //理论上满足结合律 int main()
{
//freopen("//home//chen//Desktop//ACM//in.text","r",stdin);
while(~scanf("%d%d%d%d",&n,&m,&l,&r)&&(n+m+l+r))
{
memset(save,,sizeof(save));
for(int i=;i<m;i++)
{
int tmp1;
scanf("%d",&tmp1);
tmp1=tmp1%n;//n就是走了0步
save[tmp1]++;
} memset(g,,sizeof(g));
g[]=;
for(int ii=;ii<n;ii++) //有save[ii] 个不同的
{
if(save[ii]==) continue;
//////////////////
int cnt;
while(save[ii])
{
cnt=;
memset(tmp,,sizeof(tmp));
tmp[ii+]=0.5;//因为ii+1可能会和n+1-ii相等所以下一步用+=是必须的
tmp[n+-ii]+=0.5; //wa 了N次在这一步. 思维还是想不到很全面
while(*cnt <= save[ii])
{
memset(sum,,sizeof(sum));
for(int i=;i<=n;i++) //从第一个位置开始
{
for(int j=;j<=n;j++)
{
int ttmp=i+j-;
if(ttmp > n) ttmp -= n;
sum[ttmp] += tmp[i]*tmp[j];
}
}
for(int i=;i<=n;i++)
tmp[i]=sum[i];
cnt=cnt+cnt;
}
memset(sum,,sizeof(sum)); for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
int ttmp=i+j-;
if(ttmp>n) ttmp -= n;
sum[ttmp] += g[i]*tmp[j];//每个点对其他的贡献
}
}
for(int i=;i<=n;i++)
g[i]=sum[i]; save[ii]-=cnt;
}
} double ans=;
for(int i=l;i<=r;i++)
ans += g[i];
printf("%.4lf\n",ans);
}
return ;
}
hdu 4576(简单概率dp | 矩阵优化)的更多相关文章
- HDU 3853LOOPS(简单概率DP)
HDU 3853 LOOPS 题目大意是说人现在在1,1,需要走到N,N,每次有p1的可能在元位置不变,p2的可能走到右边一格,有p3的可能走到下面一格,问从起点走到终点的期望值 这是弱菜做的第 ...
- HDU 4576 Robot(概率dp)
题目 /*********************复制来的大致题意********************** 有N个数字,M个操作, 区间L, R. 然后问经过M个操作后落在[L, R]的概率. * ...
- HDU 4576 简单概率 + 滚动数组DP(大坑)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4576 坑大发了,居然加 % 也会超时: #include <cstdio> #includ ...
- poj3744 Scout YYF I[概率dp+矩阵优化]
Scout YYF I Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8598 Accepted: 2521 Descr ...
- Aeroplane chess(简单概率dp)
Hzz loves aeroplane chess very much. The chess map contains N+1 grids labeled from 0 to N. Hzz start ...
- HDU - 2294: Pendant(矩阵优化DP&前缀和)
On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K ki ...
- CF1151F Sonya and Informatics (计数dp+矩阵优化)
题目地址 Solution (duyi是我们的红太阳) (这里说一句:这题看上去是一个概率dp,鉴于这题的概率dp写法看上去不好写,我们其实可以写一个计数dp) 首先拿到这个题目我们要能设出一个普通d ...
- POJ 3744 Scout YYF I (概率dp+矩阵快速幂)
题意: 一条路上,给出n地雷的位置,人起始位置在1,向前走一步的概率p,走两步的概率1-p,踩到地雷就死了,求安全通过这条路的概率. 分析: 如果不考虑地雷的情况,dp[i],表示到达i位置的概率,d ...
- HDU - 1099 - Lottery - 概率dp
http://acm.hdu.edu.cn/showproblem.php?pid=1099 最最简单的概率dp,完全是等概率转移. 设dp[i]为已有i张票,还需要抽几次才能集齐的期望. 那么dp[ ...
随机推荐
- j2ee高并发时使用全局变量需要注意的问题
原文:https://blog.csdn.net/jston_learn/article/details/21617311 开发中,全局变量的使用很频繁,但对于多线程的访问,使用全局变量需要注意的地方 ...
- 说说iDempiere = OSGi + ADempiere的OSGi
怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建.http://osssme.org/ 我对iDempiere还完全摸不着头脑,正好在学习之际,应erp100的@纵横四海 邀请 ...
- HTML-HTML5+CSS3权威指南阅读(三、CSS3)
不同的浏览器(包括-moz-代表的Mozilla Firefox, -ms-代表的Microsoft Internet Explorer等)厂商在发布正式版本之前之前, 试验各自对CSS3新特性的实现 ...
- GTD实用指南(转载)
时间管理第一层:记录每日时间开支,认识自己的时间黑洞.你会惊讶地发现,每天的无意义时间很可能在70%以上. [避开时间黑洞的小策略:1.彻底关闭聊天工具:2.关掉邮件的到达提醒功能:3.保持办公环境的 ...
- php 面象对象类自动加载
//自动加载第一步 function myload($class) { require('./'.$class.'.class.php'); } //注册一个函数为自动触发函数 spl_autoloa ...
- 我的Android进阶之旅------>Android关于Activity管理的一个简单封装
怎样管理当前的执行Activity栈,怎样彻底退出程序.本文封装了一个Activity管理类,能够方便随时退出程序. import java.util.Stack; import android.ap ...
- Docker Python API 与 Docker Command
span.kw { color: #007020; font-weight: bold; } code > span.dt { color: #902000; } code > span. ...
- Openresty配置文件上传下载
1. 下载包安装Openresty openresty-1.13.6.1下载地址 https://openresty.org/download/openresty-1.13.6.1.tar.gz 安装 ...
- KVC之-(id)valueForKey:(NSString *)key的实现原理与验证
KVC之-(id)valueForKey:(NSString *)key的实现原理与验证 2.-(id)valueForKey:(NSString *)key的实现原理与验证; #功能:使用一个字符串 ...
- 初识PowerShell
一.简介 Windows PowerShell 是微软公司为Windows环境所开发的壳程序(shell)及脚本语言技术,采用的是命令行界面.这项全新的技术提供了丰富的控制与自动化的系统管理能力.之前 ...