Hdu acm 3486 step5.3.6(树状数组)
来源:互联网 发布:澳大利亚旅游 知乎 编辑:程序博客网 时间:2024/04/30 14:16
Interviewe
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4389 Accepted Submission(s): 1077
Problem Description
YaoYao has a company and he wants to employm people recently. Since his company is so famous, there are n people comingfor the interview. However, YaoYao is so busy that he has no time to interviewthem by himself. So he decides to select exact m interviewers for this task.
YaoYao decides to make the interview asfollows. First he queues the interviewees according to their coming order. Thenhe cuts the queue into m segments. The length of each segment is , which meanshe ignores the rest interviewees (poor guys because they comes late). Then,each segment is assigned to an interviewer and the interviewer chooses the bestone from them as the employee.
YaoYao’s idea seems to be wonderful, but hemeets another problem. He values the ability of the ith arrived interviewee asa number from 0 to 1000. Of course, the better one is, the higher ability valueone has. He wants his employees good enough, so the sum of the ability valuesof his employees must exceed his target k (exceed means strictly large than).On the other hand, he wants to employ as less people as possible because of thehigh salary nowadays. Could you help him to find the smallest m?
Input
The input consists of multiple cases.
In the first line of each case, there aretwo numbers n and k, indicating the number of the original people and the sumof the ability values of employees YaoYao wants to hire (n≤200000, k≤1000000000). In the second line,there are n numbers v1, v2, …, vn (each number is between 0 and 1000), indicating the abilityvalue of each arrived interviewee respectively.
The input ends up with two negativenumbers, which should not be processed as a case.
Output
For each test case, print only one numberindicating the smallest m you can find. If you can’t find any, output -1instead.
Sample Input
11 300
7 100 7 101 100 100 9 100 100 110 110
-1 -1
Sample Output
3
Hint
We need 3 interviewers to help YaoYao. Thefirst one interviews people from 1 to 3, the second interviews people from 4 to6,
and the third interviews people from 7 to9. And the people left will be ignored. And the total value you can get is100+101+100=301>300.
题解:
这道题用的是区间最值和二分的方法来算出答案的。
下面是网上某位大神对区间最值的代码:
RMQ(Range Minimum/Maximum Query)问题:
RMQ问题是求给定区间中的最值问题。当然,最简单的算法是O(n)的,但是对于查询次数很多(设置多大100万次),O(n)的算法效率不够。可以用线段树将算法优化到O(logn)(在线段树中保存线段的最值)。不过,Sparse_Table算法才是最好的:它可以在O(nlogn)的预处理以后实现O(1)的查询效率。下面把SparseTable算法分成预处理和查询两部分来说明(以求最小值为例)。
预处理:
预处理使用DP的思想,f(i, j)表示[i, i+2^j - 1]区间中的最小值,我们可以开辟一个数组专门来保存f(i, j)的值。
例如,f(0, 0)表示[0,0]之间的最小值,就是num[0], f(0, 2)表示[0, 3]之间的最小值, f(2, 4)表示[2, 17]之间的最小值
注意, 因为f(i, j)可以由f(i, j - 1)和f(i+2^(j-1), j-1)导出, 而递推的初值(所有的f(i, 0) =i)都是已知的(在这里,j-1<j所以第一个循环的为列j循环,然后再进行行i的循环)
所以我们可以采用自底向上的算法递推地给出所有符合条件的f(i, j)的值。
查询:
假设要查询从m到n这一段的最小值, 那么我们先求出一个最大的k,使得k满足2^k <(n - m + 1).
于是我们就可以把[m, n]分成两个(部分重叠的)长度为2^k的区间: [m, m+2^k-1], [n-2^k+1, n];(2^k < n-m+1 -> m+2^k-1<n,m<n-2^k+1 -> 所以两个区间出现重叠,其最大值就是[m,n]区间的最大值)
而我们之前已经求出了f(m,k)为[m, m+2^k-1]的最小值, f(n-2^k+1, k)为[n-2^k+1, n]的最小值
我们只要返回其中更小的那个,就是我们想要的答案, 这个算法的时间复杂度是O(1)的.
例如, rmq(0, 11)= min(f(0, 3), f(4, 3))
由此我们要注意的是预处理f(i,j)中的j值只需要计算log(n+1)/log(2)即可,而i值我们也只需要计算到n-2^k+1即可。(预处理中,i+2^j-1 = n,i>0;j <log2(n+1);
同时还有,i+2^j -1<= n)
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
#define maxs( a , b ) a>b?a:b
#define mins( a , b ) a>b?b:a
const int MAX_N = 50005;
int d[MAX_N];
int dpmin[MAX_N][20];
int dpmax[MAX_N][20];
int n;
void create_Dpmin(){
int i , j;
for( i = 1 ; i <= n ; i++ )
dpmin[i][0] = d[i];
for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){
for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){
dpmin[i][j] = mins(dpmin[i][j-1] , dpmin[i+(1<<(j-1))][j-1] );
}
}
}
void create_Dpmax(){
int i , j;
for( i = 1 ; i <= n ; i++ )
dpmax[i][0] = d[i];
for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){
for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){
dpmax[i][j] = maxs(dpmax[i][j-1] , dpmax[i+(1<<(j-1))][j-1] );
}
}
}
int getmax( int a , int b ){
int k = (int)(log((double)(b-a+1))/log(2.0));
return maxs( dpmax[a][k] , dpmax[b-(1<<k)+1][k] );
}
int getmin( int a , int b ){
int k = (int)(log((double)(b-a+1))/log(2.0));
return mins( dpmin[a][k] , dpmin[b-(1<<k)+1][k] );
}
void Init()
{
create_Dpmin();
create_Dpmax();
}
int main()
{
freopen( "in.txt" , "r" , stdin );
int i , m , a , b;
scanf("%d%d",&n,&m);
for( i = 1 ; i <= n ; i++ ){
scanf("%d",&d[i]);
}
Init();
while( m-- ){
scanf("%d%d",&a,&b);
printf("%d\n",getmax(a,b)-getmin(a,b));
}
return 0;
}
而如果只用二分和区间最值还是会超时,所以有一个解题的步骤,就是记录如果N/k(N为总人数,k为留下的人数)的队伍人数相同(即当N/k==N/(k+1)每队只留下一个人的话),即sum的值不用改变再加上新来的人的价值。
用G++超时,用c++不超时。
源代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define maxs(a,b) a>b?a:b;
#define MAX 200050
int d[MAX];
int dpmax[MAX][20];
int n,v;
void create_dpmax()
{
for(int i = 1;i <= n;i++)
dpmax[i][0] = d[i];
for(int j = 1;j <= log((double)(n+1))/log(2.0);j++)
{
for(int i = 1;i+(1<<j)-1 <= n;i++)
{
dpmax[i][j] = maxs(dpmax[i][j-1],dpmax[i+(1<<j-1)][j-1]);
}
}
}
int getmax(int a,int b)
{
intk = (int)(log((double)(b-a+1))/log(2.0));
returnmaxs(dpmax[a][k],dpmax[b-(1<<k)+1][k]);
}
int main()
{
while(scanf("%d%d",&n,&v) != EOF)
{
if(n== -1 && v == -1)
break;
for(int i = 1;i <= n;i++)
scanf("%d",&d[i]);
create_dpmax();
intk = 1,flag = 1,m,pre = -1,ps,pos=0,j,sum= 0;
while(k<= n)
{
j = n/k;
m = j*k;
if(j== pre)
pos = ps;
else
{
pos = 0;
sum = 0;
}
while(pos+j<= m)
{
sum += getmax(pos+1,pos+j);
if(sum> v)
{
printf("%d\n",k);
flag = 0;
break;
}
pos += j;
}
if(!flag)
break;
ps = m;
pre = j;
k++;
}
if(k> n)
printf("-1\n");
}
return0;
}
- Hdu acm 3486 step5.3.6(树状数组)
- Hdu 2838 step5.3.7 (树状数组)
- Hdu 1892 step5.3.1 See you~(树状数组)
- hdu step5.3.3 Median Filter(树状数组求第k大的值)
- [ACM] hdu 2352 Stars (树状数组)
- HDU 5096 ACM Rank(树状数组)
- 树状数组(acm hdu 5792)
- [ACM] hdu 1166 敌兵布阵(树状数组)
- 杭电 HDU ACM 1166 敌兵布阵(树状数组)
- HDU ACM 5249 KPI->树状数组+二分
- Hdu1166 step5.3.2敌兵布阵(简单的树状数组)
- [ACM] hdu 5147 Sequence II (树状数组,前缀和,后缀和)
- HDU 5869 ACM-ICPC Regional Dalian Online(离线统计+树状数组)
- HDU 5517 Triple ACM/ICPC 2015 Shenyang(二维树状数组)
- HDU 6203 ping ping ping (LCA + 树状数组, 2017 ACM/ICPC Asia Regional Shenyang Online)
- HDU ACM 4046 Panda 线段树或者树状数组
- HDU ACM 3887 Counting Offspring 树状数组+DFS
- HDU 5517 (ACM 2015 沈阳) Triple [树状数组]
- c中如何输出一个宏定义的字符串?
- 怎么在阿里妈妈投放广告?--人人有责-- .
- cocos2dx CrystalCraze 宝石消除游戏 解析(二)
- 美化MFC控件,OnCtlColor() in MFC
- emoji 表情 编码整理
- Hdu acm 3486 step5.3.6(树状数组)
- 一步步学习SPD2010--第二章节--处理SP网站(3)--创建网站层次架构
- Jxl简单使用(Excel)
- Hibernate调用Oracle的存储过程
- [Linux/Ubuntu] vi/vim 使用方法讲解
- 总结了Struts1与Struts2的11点区别
- 剑指offer(35)-两链表的第一个公共结点[数据结构]
- Ubuntu12.04搭建BigBlueButton
- 【SQL Server数据迁移】64位的机器:SQL Server中查询ORACLE的数据