codeforces 479E Riding in a Lift dp+前缀数组优化
2015-08-22 11:02
232 查看
http://codeforces.com/contest/479/problem/E
dp,我这dp弱狗都看出来了,这题dp不是很难想到,比较不容易的是如何优化,使得不会T。
题意:
给定一个启示的楼层a,有一个不能去的楼层b,对于你可以去的下一个楼层必须满足你当前楼层x与下一个要去的楼层y的距离小于x到b的距离。求出走k趟的方案数。
思路:
可以定义dp[i][j]表示第i趟的时候到第 j 楼层的方案数。
转移方程dp[i][j] += dp[i-1][k] (k = 1,….,n)
很容易写出一个O(n3n^3)的算法,对于每一趟枚举每一个楼层,再对于每个楼层枚举前一个楼层,判断是否可以转移。
但是发现10510^5并不可搞。
优化方案:
会发现查找前一个楼层的时候需要O(nn),复杂度太高。但是仔细观察会发现对于当前的楼层,上一个楼层能转移到当前楼层的地方都很有规律,都是成段的。这样就可以运用一个比较常见的优化方法了,就是运用前缀数组来记录在前一趟中到达这个点以前的方案总数有几种。这样对于任意一个成段的满足的线段都可以求出在这个区间内的方案总数了,将转移状态的复杂度降至O(11)。此时可以分类讨论,如果当前楼层在b的左边可以求出之前转移的一段线段,右边又是一种。
在转移完之后要记得扣掉前一趟也在这个楼层之中的情况。
模运算注意事项:
这题还涉及到取模运算,在取模运算的时候要小心,如果是两个取模后的值相减再取模,很可能会出现负数,可以加上一个mod,以消除影响。
dp,我这dp弱狗都看出来了,这题dp不是很难想到,比较不容易的是如何优化,使得不会T。
题意:
给定一个启示的楼层a,有一个不能去的楼层b,对于你可以去的下一个楼层必须满足你当前楼层x与下一个要去的楼层y的距离小于x到b的距离。求出走k趟的方案数。
思路:
可以定义dp[i][j]表示第i趟的时候到第 j 楼层的方案数。
转移方程dp[i][j] += dp[i-1][k] (k = 1,….,n)
很容易写出一个O(n3n^3)的算法,对于每一趟枚举每一个楼层,再对于每个楼层枚举前一个楼层,判断是否可以转移。
但是发现10510^5并不可搞。
优化方案:
会发现查找前一个楼层的时候需要O(nn),复杂度太高。但是仔细观察会发现对于当前的楼层,上一个楼层能转移到当前楼层的地方都很有规律,都是成段的。这样就可以运用一个比较常见的优化方法了,就是运用前缀数组来记录在前一趟中到达这个点以前的方案总数有几种。这样对于任意一个成段的满足的线段都可以求出在这个区间内的方案总数了,将转移状态的复杂度降至O(11)。此时可以分类讨论,如果当前楼层在b的左边可以求出之前转移的一段线段,右边又是一种。
在转移完之后要记得扣掉前一趟也在这个楼层之中的情况。
模运算注意事项:
这题还涉及到取模运算,在取模运算的时候要小心,如果是两个取模后的值相减再取模,很可能会出现负数,可以加上一个mod,以消除影响。
[code]#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 5009 #define mod 1000000007 typedef long long ll; int dp[M][M]; int pre[M]; int ans; int n,a,b,kk; int main() { while(scanf("%d %d %d %d",&n,&a,&b,&kk)==4) { ans = 0; memset(dp,0,sizeof(dp)); dp[0][a] = 1; for(int i = 1;i <= kk;i++) { pre[0] = 0; for(int j = 1;j <= n;j++) pre[j] = (pre[j-1]+dp[i-1][j])%mod; //记录前一趟中j以前的点(包括j)的方案总数 for(int j = 1;j <= n;j++) { if(j == b) continue; if(j < b) { dp[i][j] = (pre[(abs(j-b)-1)/2+j]+mod)%mod; //小心小于而不能等于的条件 } else { dp[i][j] = (pre - pre[j-(abs(j-b)+1)/2]+mod)%mod; } dp[i][j] = (dp[i][j] - dp[i-1][j]+mod)%mod; //取模相减的时候记得要+mod以消除影响 } } int b; for(int i = 1;i <= n;i++) ans = (ans + dp[kk][i])%mod; printf("%d\n",ans); } return 0; }
相关文章推荐
- Java-6-IO
- Memory Leak(内存泄漏)问题总结
- Hibernate中的一对一关系详解(1)
- web也是区分前端与后端的,session\cookie辨析
- 1.Linux环境下的Nuttx开发环境搭建
- 【树状数组】POJ 2155 Matrix
- java SWT中Label实时刷新当前时间
- C++模板的理解与使用
- 通过配置tomcat虚拟路径配置站点的静态资源
- Java-5-异常
- Go语言中的复合类型及面向对象思想
- 堆(heap)和栈(stack)、内存泄漏(memory leak)和内存溢出
- Struts(15)类型转换
- centos开启ftp服务
- C++模板的理解与使用
- hdu2149 巴什博奕
- 通过配置tomcat虚拟路径配置站点的静态资源
- 阶乘、斐波那契、 1的个数统计 c语言 实现备忘
- Java-4-重载多态
- 14 Longest Common Prefix