有n个人参加编程比赛,比赛结束后每个人都得到一个分数;现在所有人排成一圈(第一个和第n个相邻)领取奖品,要求;
1:如果某个人的分数比左右的人高,那么奖品数量也要比左右的人多;
2:每个人至少得到有个奖品。
问最少应该准备多少奖品。
输入描述:
第一行是整数n,表示测试样例个数
每个测试样例的第一行是一个正整数n,表示参加比赛的人数;(0<n<100000)
第二行是n个正整数a[i](0<a[i]<100000),表示的从第1个人到第n个人的分数。
输出描述:
对每个测试样例,输出应该准备的最少奖品。
样例:
2
2
1 2
4
1 2 3 3
输出
3
8
思路:
其实从左往右遍历一遍,得到1个序列,然后从右往左遍历一下,得到第2个序列,然后最后取较大值,最后累加即可。
代码:
盖力:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX = 100000+10;
int a[MAX];
int ans1[MAX];
int ans2[MAX];
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int min_index = 0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]<a[min_index]) min_index = i;
}
// printf("%d\n",min_index);
ans1[min_index] = 1;
int cur = min_index;
bool flag = false;
int next = (cur+1)%n;
while( cur!= min_index || !flag)
{
flag = true;
if(a[next]>a[cur]) ans1[next] = ans1[cur] +1 ;
else ans1[next] = 1;
cur = (cur+1)%n;
next = (cur+1)%n;
}
cur = min_index;
next = (cur-1+n)%n;
ans2[min_index] = 1;
flag = false;
while(cur!= min_index || !flag)
{
flag = true;
if(a[next]>a[cur]) ans2[next] = ans2[cur] +1 ;
else ans2[next] = 1;
cur = (cur-1 +n)%n;
next = (cur-1+n)%n;
}
int ans = 0;
for(int i = 0 ;i < n ;i++)
ans += max(ans1[i],ans2[i]);
printf("%d\n",ans);
}
return 0;
}
第二题:
有N跟绳子,第i根绳子长度为Li,现在需要M根等长的绳子,你可以对n根绳子进行任意裁剪(不能拼接),请你帮忙计算出这m根绳子最长的长度是多少。
输入描述:
第一行包含2个正整数N,M,表示N根原始的绳子,和最终需要M跟绳子
第二行包括N个整数,第i个整数Li表示第i根绳子的长度
其中
1<=N、M<=100000
0< Li<1000000000000
输入3 4
3 5 4
输出2.5
解析:
二分,对绳子的长度进行二分,然后看是否满足大于等于M个等长的条件。
代码:
盖力:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define eps 1e-6
const int maxn = 100000+10;
double a[maxn];
bool Judge(double mid, int n, int m)
{
int cnt = 0;
for(int i = 0 ;i<n; i++)
cnt += (int)(a[i]/mid);
if(cnt>=m) return true;
return false;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
double l,r,mid;
r = -1;
for(int i=0;i<n;i++)
{
scanf("%lf",&a[i]);
r = max(r,a[i]);
}
l = 0;
while(r-l>eps)
{
mid = (l+r)/2;
if(Judge(mid,n,m)) l = mid;
else r = mid;
}
printf("%.2f\n",l);
}
return 0;
}