您的位置:首页 > 编程语言 > Java开发

SRM539-div1-1-div2-2-Over9000Rocks

2012-04-08 21:27 260 查看
zz:
http://www.strongczq.com/2012/04/srm539-div1-1-div2-2-over9000rocks.html
题目原文:
http://community.topcoder.com/stat?c=problem_statement&pm=11855
[align=left]
[/align]
[align=left]题目大意:[/align]
[align=left]     从若干个盒子中任意选择几个装石头,每个盒子容量都有上下限,一旦选择使用某个盒子,那么填装的石头数必须在该盒子的上下限容量之间。假设最终填装的石头总数为X,那么符合条件X>9000的X有多少个?[/align]
[align=left]     数据规模:盒子总数[1,15], 盒子容量[1,10^6][/align]
[align=left]
[/align]
[align=left]思路:[/align]
[align=left]     由于盒子数的最大值只有15,所以可以遍历所有的盒子选择方案,总共2^15=32K种。在每一种选择方案中,累加所有盒子的容量下限和上限作为总的容量下限和上限(下限要与9001取最大值),总容量下限都上限之间的所有值都是X的可能值。汇总所有方案下的所有取值(需要去重)就可以得到最终结果。[/align]
[align=left]     由于每种方案下的取值区间最小值都可以达到接近10^6,所以一个个记录可能取值肯定会超时的(2^15*10^6)。好在我们只需要记录每中方案下的取值范围起始值和终止值便可。最终根据这些记录的范围来计算所有可能取值数。有两种实现方式(假设盒子数为k):[/align]

保存每种方案下的取值范围二元组[s,t],总共有2^k。对这些二元组进行从小到大排序,二元组中s为主键,t为第二主键。然后从小到大扫描这些二元组,过程中保留目前所遇到的X可行取值的最大值lastMax。对于当前二元组[s,t],分别比较s、t与lastMax的大小关系去除重复的取值,将新发现的取值范围的长度加到最终结果中,然后更新lastMax。
利用一个大小为15×10^6+2的数组short[] bound保存各方案下的取值范围,假设某个方案的取值范围是[s,t],则bound[s]++, bound[t+1]--。然后遍历从9001到15×10^6的每个值x,考虑bound[9001]+bound[9002]+...+bound[x]的取值,如果大于0则说明x处于某个取值范围中,否则不是。(该数组的大小可以优化为所有盒子容量上限的加和)。
     第二种方法在最坏情况下空间和时间消耗都更大,但是编码更简单些,以下代码使用第二种实现方式。

Java代码:

public class Over9000Rocks {
public int countPossibilities( int[] lowerBound, int[] upperBound) {
int n = lowerBound.length ;
int maxRes = 0;
for (int i = 0; i < n; ++i){
maxRes += upperBound[i];
}
int [] bound = new int[maxRes + 2];
for (int m = 1; m < (1 << n); ++m) {
int low = 0, up = 0;
for (int i = 0; i < n; ++i) {
if ((m & (1 << i)) > 0) {
low += lowerBound[i];
up += upperBound[i];
}
}
low = Math. max(low, 9001);
if (up < low) {
continue ;
}
bound[low]++;
bound[up + 1]--;
}
int res = 0;
int v = 0;
for (int x = 9001; x <= maxRes; ++x){
if ((v += bound[x]) > 0){
res++;
}
}
return res;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  up class java 优化