1.广告排名区间(10分)
问题背景
shifen广告消费预估系统可以估计出一段时间内一个特定的广告在检索结果中排在各个位置的几率。比如系统对某广告的输出如下:
p1=0.03,p2=0.08,p3=0.04……
这说明该广告展现在第1位的概率是3%,展现在第2位的概率是8%,展现在第3位的概率是4%……
问题是:如何给出一个排名估计区间[i,j],使得广告出现在该区间中的概率大于或等于一个预设值p,同时这个区间所包含的元素尽可能的少。也可用数学语言来描述:给定数p和数列p1,p2,…,pn,求i和j(1<=i<=j<=n),在满足pi+pi+1+…+pj>=p的前提下让j-i最小。
一般来说,pi只需保留6位小数就足够了。这样,若令ai=106pi,a=106p,则a和所有的ai均为[0,106]之间的整数。这样就避免了对实数的处理。
输入格式
第一行包含一个整数n(1<=n<=100,000)。
以下n行每行包含一个[0,106]内的整数,依次为a1,a2,…,an。这n个整数之和保证不超过106。
最后一行包含一个[0,106]内的整数a。保证所有ai之和不小于a。
输出格式
输出仅一行,包含一个整数,即j–i的最小值。
样例输入
7
5
8
4
7
10
5
2
18
样例输出
2
样例解释
a2=8,a3=4,a4=7之和为19,满足条件。而任何两个相邻数之和均小于18。
基本方法:想用快捷的方法保留部分和,到最后自己已经糊涂了,经过修改,不过还是可以输出正确结果
php代码:
<?php
//广告排名区间
$p=array(5,1,1,1,1,1,8,1,1,4,1,1,7,1,5,1,2,1,1,1,1,1,1,30,1,1,5,1,1,1,1,1,8,1,11,11,6,1,1,1,1,11,1,2,3,5);//概率数组
$max=30;//临界值
//给定初始点,判断结束点,根据结束和-初始点-结束点=下次的初始和,并给出初始长度
$wz=0;
$len=0;
$he=0;
$jishu=0;
$qujian_len1=0;//保存的区间长度
while($wz<count($p)){//echo $wz;
$isyou=0;
$new=0;//是否会有比上次更小的区间
$chaoguo=0;//是否超过先前最小区间仍没有结果
for($i=$wz;$i<count($p);$i++){
$he=$he+$p[$i];
$qujian_len=$len+$i-$wz+1;//区间长度
if($qujian_len>$qujian_len1&&$jishu>0){//echo 2;
$wz=$wz-$len+1;$len=0;$he=0;$chaoguo=1;break;}
//路过和大于了临界值,记录此时位置,这个位置就是下次的起点,求起点和
if($he>=$max){
//echo 1;
//路过区间小于上一个的,更新
if($qujian_len<$qujian_len1||$jishu==0)
{$jishu++;
$savehe=$he;
$he=$savehe-$p[$wz]-$p[$i];
$kswz=$wz-$len;
$jswz=$i;
$wz=$i;
$qujian_len1=$qujian_len;
$len=$qujian_len-2;//重设初始长度
if($len<0)$len=0;
$new=1;
}//end if($qujian_len>$qujian_len1)
$isyou=1;
break;
}//end if($he>=$max)
}//end for($i=$wz;$i<count($p)
if($new==0){$wz=$wz-$len+1;$len=0;$he=0;}
if($isyou==0&&$chaoguo==0)break;//路过该次循环到结尾无结果,结束
}//end while($wz<count($p))
if($jishu>0)echo '开始索引:'.$kswz.'-------结束索引:'.$jswz.'-----区间最小长度:'.$qujian_len1.'----和为:'.$savehe;
else echo '无解';
?>