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[ ...
随机推荐
- Struts2中的变量
<package name="mypackage" extends="struts-default"> <global-results> ...
- Actors编程模型
Actors模型(Actor model)首先是由Carl Hewitt在1973定义, 由Erlang OTP (Open Telecom Platform) 推广,其 消息传递更加符合面向对象的原 ...
- Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet] 异常
1. 异常描述 FATAL EXCEPTION: main Process: com.whereru.greengrass.goforit, PID: 13847 java.lang.RuntimeE ...
- ContentObserver与DatasetObserver区别
1. ContentObserver ContentObserver主要是通过Uri来监测特定的Databases的表,如果该Databases表有变动则会通知更新cursor中的数据. 如果 ...
- C++的泛型编程方式
1.使用类模板创建数组 下面这段代码:是创建一个元素为 T 类型的数组. #pragma once template<class T> class MyArray { public: // ...
- POI操作Excel导入和导出
Apache的POI组件是Java操作Microsoft Office办公套件的强大API,当中对Word,Excel和PowperPoint都有支持,当然使用较多的还是Excel.由于Word和Po ...
- sql server中Join有几种
JOIN: 如果表中有至少一个匹配,则返回行 (也就是 inner join)LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有 ...
- jquery遍历总结(转)
遍历 DOM jQuery 提供了多种遍历 DOM 的方法. 遍历方法中最大的种类是树遍历(tree-traversal). 下一章会讲解如何在 DOM 树中向上.下以及同级移动. 向上遍历 DOM ...
- 优化数据页面(22)——n:n的数据关系
设计要点:优化数据页面.界面设计.美化exce 阿金:那n::n就复杂了,你倒是想留有空间. 可是现实社会有时却不同意. 秀秀:唉.说的也是. 阿金:那怎么表达才合适啊? 秀秀:仅仅实用网格了. 阿金 ...
- CentOS6X安装PHP5.5
CentOS6.x默认的php版本是php5.3,已经过时喽,现在最新的稳定版是5.5.38. 安装方法: 1.先下载2个源 rpm -Uvh https://dl.fedoraproject.org ...