angryA (USACO 2016 JAN Bronze)
题目描述
牛奶Bessie设计了一个游戏:“愤怒的牛奶”。游戏的原型是:有一些可爆燃的草堆分布在一条数轴的不同坐标,玩家用弹弓把一头奶牛发射到数轴上。牛奶砸到草堆上的冲击能量会引发草堆燃爆,并有可能引起附近的草堆连环燃爆。游戏的目标是玩家用一头奶牛燃爆尽可能多的草堆。
有N个草堆在数轴的不同位置,坐标为x1,x2,….,xn。如果玩家把牛发射到坐标是x的草堆上,这个草堆就会燃爆,冲击波的半径是1,距离它是1的草堆也会被燃爆。这些相邻的草堆会同时燃爆,并且冲击波的半径是2。下一步,被燃爆的草堆冲击波半径会是3。一般的,时间t燃爆的草堆,每一个的冲击波半径是t,被这些冲击波引爆的草堆在t+1时刻会产生冲击波半径是t+1,以此类推。
请计算,只用一头奶牛玩家最多可以燃爆多少草堆?
输入格式
第一行:一个整数N( 1 ≤ N ≤ 100)。
下面有N行,每行一个整数:x1, x2 ,…,xn,范围在[0…1,000,000,000]
输出格式
输出最大可能燃爆的草堆数。
输入样例
6
8
5
6
13
3
4
输出样例
5
【题意分析】
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,ans;
int a[110];
bool bo[110];
void f(int w,int t)
{
int p,q;
p=1;
while( a[w] - a[w-p] <= t && a[w] - a[w-p] >=0 && w-p>0 &&bo[w-p]) //在这个冲击半径内,能引爆几个的草堆?(左边)
{
ans++; //草堆个数加 1
bo[w-p]=0; //被引爆
p++;
}
q=p-1;
p=1;
while( a[w+p] - a[w] <= t && a[w+p] - a[w] >=0 && w+p<=n &&bo[w+p]) //在这个冲击半径内,能引爆几个的草堆?(右边)
{
ans++; //草堆个数加 1
bo[w+p]=0; //被引爆
p++;
}
p--;
if(w-q>0&&q>0)
f(w-q,t+1);//左边
if(w+p<=n&&p>0)
f(w+p,t+1);//右边
}
int main()
{
int maxx=-0x0fffffff;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
memset(bo,1,sizeof(bo));
ans=1;
bo[i]=0;//奶牛直接引爆
f(i,1);
maxx=max(maxx,ans);//保存最大值
}
printf("%d",maxx);
return 0;
}
【B:angry cows SLIVER】
angryB (USACO 2016 JAN silver)
牛奶Bessie设计了一个游戏:“愤怒的牛奶”。游戏的原型是:有一些可爆燃的草堆分布在一条数轴的不同坐标,玩家用弹弓把奶牛发射到数轴上。牛奶砸到数轴上的冲击波会引发附近的草堆燃爆,并有可能引起附近的草堆连环燃爆。游戏的目标是玩家用一些奶牛燃爆所有的草堆。
有N个草堆在数轴的不同位置,坐标为x1,x2,….,xn。如果玩家把奶牛发射到坐标是x,能量是R,就会引爆半径R以内的的草堆,即坐标范围[x-R, x+r]的草堆都会燃爆。
现在有K头奶牛,每头奶牛的能量都是R,请计算如果要引爆所有的草堆,最小的R是多少?
输入格式
第一行:2个整数N( 1 ≤ N ≤ 50,000)和K( 1 ≤ K ≤ 10)。
下面有N行,每行一个整数:x1, x2 ,…,xn,范围在[0…1,000,000,000]
输出格式
输出最小可能的R。
输入样例
7 2
20
25
18
8
10
3
1
输出样例
5
【题意分析】
数据是50000,所以,O(n^2)的算法(直接枚举R)是不可取的。所以,我们可以二分R,并记要引爆所有草堆最少需要奶牛的个数为sum,假如奶牛的个数大于等于题目中所描述的K,然后就向右边缩小范围(即l=mid+1),因为这时侯R的值太小了;否则就向左缩小范围(r=mid)。最后输出l,就可以了。
现在问题来了:怎样计算最少的奶牛个数?我们可以用last记为从0到last的草堆已被炸掉(那么前面就要先把草堆进行排序),那么只要用贪心,在x[ last+1 ]+R的地方把奶牛扔过去,再统计能被引爆的个数并加到last上。直到草堆全部炸完为止。这样时间复杂度是O(n)。
#include<cstdio>
#include<algorithm>
using namespace std;
int minx=0x0fffffff,maxx=-0x0fffffff;
int a[50011];
int n,k,l,r,mid;
int t,sum,ans=0x0fffffff,p;
int last;
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
minx=min(minx,a[i]);
maxx=max(maxx,a[i]);
}
sort(a,a+n); //把草堆的位置排序
l=0; r=maxx-minx;
while(l<r)//二分R
{
mid=(l+r)/2;
last=0;
sum=0;
t=0;
while(last<n)//统计最少需要奶牛的个数
{
t=a[last+1]+mid;
p=last+1;
while(p<n && a[p]-a[last]<=(mid<<1)) p++;
last=p;
sum++;
}
if(sum<=k) r=mid;
else l=mid+1;
}
printf("%d",l);//输出最少的R
return 0;
}