hdu 3486(RMQ+高效枚举)
2016-05-05 20:04
204 查看
题意:把n分为 均分为m 段 每段n/m个数字 每段可以选一个最大的数 求这些数相加起来>k的最小的m
解题思路:这道题本来想用二分+rmq的,但discuss里面说二分是错的,所以只能另想别的办法了。
首先是可以肯定的,一定要枚举段数,接下来就是如何减少对内层循环的枚举次数。
当分成i段得到的段长L1
与 之前分成 i-1段得到的段长相同 那就只要把前一次的结果再加上这一次 第i段的最大值 就是当前的结果了 这一步少做了很多步骤 节约了很多时间
解题思路:这道题本来想用二分+rmq的,但discuss里面说二分是错的,所以只能另想别的办法了。
首先是可以肯定的,一定要枚举段数,接下来就是如何减少对内层循环的枚举次数。
当分成i段得到的段长L1
与 之前分成 i-1段得到的段长相同 那就只要把前一次的结果再加上这一次 第i段的最大值 就是当前的结果了 这一步少做了很多步骤 节约了很多时间
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int maxn = 200005; int n,m,a[maxn],dp[maxn][20]; void init() // 从点i开始 长1<<j 的最大值 { for(int i = 1; i <= n; i++) dp[i][0] = a[i]; for(int j = 1; (1<<j) <= n; j++) for(int i = 1; i + (1<<j) - 1 <= n; i++) dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int rmq(int l,int r) { int k = (int)(log(r - l + 1.0) / log(2.0)); return max(dp[l][k],dp[r-(1<<k)+1][k]); } int solve() { int prev = -1,sum,j,left,right; for(int i = 1; i <= n; i++)//段数 { int l = n / i; if(prev != l) { j = 1; sum = 0; } while(j <= i) { left = (j-1) * l + 1; right = j*l; sum += rmq(left,right); if(sum > m) return i; j++; } prev = l; } return -1; } int main() { while(scanf("%d%d",&n,&m),n != -1,m != -1) { for(int i = 1; i <= n; i++) scanf("%d",&a[i]); init(); printf("%d\n",solve()); } return 0; }
相关文章推荐
- C#编程中枚举类型的使用教程
- 枚举的用法详细总结
- PHP中Enum(枚举)用法实例详解
- c#入门之枚举和结构体使用详解(控制台接收字符串以相反的方向输出)
- 理解C#中的枚举(简明易懂)
- C#枚举中的位运算权限分配浅谈
- C++基础入门教程(四):枚举和指针
- FileShare枚举的使用小结(文件读写锁)
- Java枚举类用法实例
- 枚举窗口句柄后关闭所有窗口示例
- javascript模拟枚举的简单实例
- 深入剖析JavaScript中的枚举功能
- 枚举和宏的区别详细解析
- 深入理解C#中的枚举
- C#实现获取枚举中元素个数的方法
- 结合C++11的新特性来解析C++中的枚举与联合
- java中枚举的详细使用介绍
- java枚举的使用示例
- Java枚举详解及使用实例(涵盖了所有典型用法)
- Java的枚举类型使用方法详解