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[ ...
随机推荐
- iOS 移动端生成工具开发
代码地址如下:http://www.demodashi.com/demo/11284.html 一.准备工作 编译环境 xcode 用于生成冗余架构代码, 实现生成零耦合架构 二.程序实现 上个月的一 ...
- iOS应用程序开发之应用间的跳转
简介 配置和实现 判断应用启动方式 一.简介 最实际项目开发中,我们难免会遇到需要从一个应用跳转到另一个应用的情况.比如微信分享,实际就是一种应用间的跳转.但是有时候我们需要实现自己的两个应用间的跳转 ...
- Android Studio 新手常见错误:Gradle DSL method not found: 'runProguard()'
在Android Studio上执行Github上的某Android开源项目,提示报错: Error:(20, 0) Gradle DSL method not found: 'runProguard ...
- 解决Janusgraph索引状态不变更的问题
JanusGraph的索引因为要同步不同实例及不同后端的数据,因此不是实时能够完成的,视配置,网络和数据量不同,建立/生效索引通常需要一段时间,这也是为什么创建索引时会创建wait()的原因. 在实践 ...
- Javascript 中使用Json的四种途径
1.jQuery插件支持的转换方式: 复制代码代码如下: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象 ...
- Springboot读取配置文件的两种方法
第一种: application.yml配置中的参数: zip: Hello Springboot 方法读取: @RestController public class ControllerTest ...
- Android Studio怎样import module(针对非gradle)
相同的,非gradle编译的project和gradle编译的在import module上相同有一些差别. 包含操作上,显示上的一些差别,曾经的文章中,仅仅要没有标注"非gradle&qu ...
- makefile之findstring函数
#$(findstring <find>,<in> ) #功能:在字串<in>中查找<find>字串. #返回:如果找到,那么返回<find> ...
- 如何让linux加载当前目录的动态库
debian从7.0开始支持multiarch,64位库的路径改到/usr/lib/x86_64-linux-gnu了,mint.ubuntu这些衍生版有没有跟着改我就不清楚了. deepin lin ...
- R学习----数据类型
今天开始学习R语言了,没原因,就是想学 本人开发环境在ubuntu 16.04 LTS下 R命令提示符 终端直接输入R进入交互模式进行R学习.如下图 R脚本 # My first program in ...