主题:第51次编程比赛
renew [专家分:200] 发布于 2007-03-22 18:02:00
题目:训练场上n(1≤n≤50000)个[b][color=FF0000]高矮都不相同[/color][/b]的士兵[b]从左到右[/b]排成一行,依次编号为1,2,…,n。第i个士兵的身高H(i),由于采用特殊单位,H(i)满足1≤H(i)≤2000000000。设第i个士兵右侧最近的比他个高的士兵编号为j,则第i个士兵可看到在他的右侧比他矮的士兵的个数S(i)=j-i-1。(不考虑客观因素,比如视力范围等-,-)
求S(1)+S(2)+…+S(n)。
输入:
标准输入。
第一行为整数n,表示士兵的个数。
第二行n个整数,用一个空格隔开。分别表示编号为1,2。。。n的士兵的身高
输出:
S(1)+S(2)+…+S(n)的结果
例:
输入
6
10 3 7 4 12 2
输出
5
例子说明:
S(1) = 3
S(2) = 0
S(3) = 1
S(4) = 0
S(5) = 1
S(6) = 0
S(1)+S(2)+S(3)+S(4)+S(5)+S(6) = 3+0+1+0+1+0 = 5
最后更新于:2007-03-26 00:19:00
回复列表 (共65个回复)
21 楼
tianbian [专家分:0] 发布于 2007-03-23 10:31:00
??????????
22 楼
goal00001111 [专家分:4030] 发布于 2007-03-23 10:44:00
#include <iostream>
#include <time.h>
using namespace std;
int Sum(int h[], int n);
int main(void)
{
time_t startTime;
time_t endTime;
const int n = 50000;
int h[n] = {0};
int temp, p;
//获取互不相同的一组数列
for (int i=0; i<n; i++)
h[i] = i + 1;
for (int i=n-1; i>0; i--)//洗牌,使得数的大小随机排列
{
p = rand()%i;
temp = h[i];
h[i] = h[p];
h[p] = temp;
}
//计时
time(&startTime);
int s;
for (int i=1; i<30000; i++)
s = Sum(h, i);
time(&endTime);
cout << "sum = " << s << endl;
cout << "time = " << difftime(endTime, startTime) << endl;
system("pause");
return 0;
}
int Sum(int h[], int n)
{
int sum = 0;
int i, t;//i作为原数组元素的下标,用来遍历原数组;t表示临时数组的长度-1
int *a = new int[n];//设置一个临时数组来存储原数组中的递减序列
a[0] = h[0];
for (t=0,i=1; i<n; i++)
{
if (h[i] < h[i-1])//如果是递减序列,复制到临时数组,并累积S(i)之和
{
a[++t] = h[i];
sum += t;
}
else//如果出现一个比其左边的人高的士兵
{
while (t > 0 && a[t-1] < h[i])//该士兵左移,直到队伍最左或者遇到比他高的人
t--;
a[t] = h[i];
sum += t;//累积S(i)之和
}
}
delete []a;
return sum;
}
23 楼
tiantangniao223 [专家分:1860] 发布于 2007-03-23 12:41:00
试试看呵呵
/******************************************************************
** 文件名: Programfan.cpp
** 创建人: tiantangniao223
** 日 期: 2007 03 23
** 修改人:
** 日 期:
** 描 述: 程序的输入采用标准输入,如果输入的士兵的身高个数超出士兵的人数
** 程序将忽略超出的数据处理
** 版 本: 1.1
**-----------------------------------------------------------------------------
******************************************************************/
#include<iostream>
using namespace std;
int main()
{
int n=0;//士兵的人数
int i=0,j=0;//循环变量
int count=0;//用于记录比当前士兵矮的士兵人数
int sum=0;//符合条件的士兵总数
cout<<"请输入士兵人数n(1<=n<=50000):"<<endl;
cin>>n;
while(n<1||n>50000)//检查士兵人数 n 是否合法
{
cout<<"输入n不符合要求!!!!!"<<endl;
cout<<"请重新输入士兵个数:(1<=n<=50000)"<<endl;
cin>>n;
}
long *H=new long[n+1];
for(i=0;i<=n;i++)//初始化分配的数组
H[i]=0;
cout<<"请输入的士兵身高H(1<=H<=2000000000):"<<endl;
for(i=1;i<=n;i++)
cin>>H[i];
for(i=1;i<=n;i++)//检查士兵的身高是否有小于1或是大于2000000000的数据
{
while(H[i]<1||H[i]>2000000000)
{
cout<<"输入的士兵身高不符合要求!!!"<<endl;
cout<<"输入的士兵身高中有小于1或是大于2000000000的数据!"<<endl;
cout<<"请重新输入 "<<n<<" 个士兵的身高:(1<=H<=2000000000)"<<endl;
for(j=1;j<=n;j++)
cin>>H[j];
}
}
for(i=1;i<=n;i++)//检查士兵的身高中是否有相等的数据
{
for(j=i+1;j<=n;j++)
{
if(H[i]==H[j])
{
cout<<"输入的士兵身高不符合要求!"<<endl;
cout<<"输入的士兵身高中有相等的数据!!!"<<endl;
cout<<"请重新输入 "<<n<<" 个士兵的身高:(1<=H<<2000000000)"<<endl;
for(j=1;j<=n;j++)
cin>>H[j];
break;
}
}
}
for(i=1;i<=n;i++)//进行比较
{
for(j=i+1;j<=n;j++)
{
if(H[i]<H[j])//如果右侧有比他高的,则结束本次比较
break;
count++;
}
sum+=count;
count=0;
}
cout<<sum<<endl;
delete[] H;
return 0;
}
24 楼
tiantangniao223 [专家分:1860] 发布于 2007-03-23 12:45:00
试试看呵呵
/******************************************************************
** 文件名: Programfan.cpp
** 创建人: tiantangniao223
** 日 期: 2007 03 23
** 修改人:
** 日 期:
** 描 述: 程序的输入采用标准输入,如果输入的士兵的身高个数超出士兵的人数
** 程序将忽略超出的数据处理
** 版 本: 1.1
**-----------------------------------------------------------------------------
******************************************************************/
#include<iostream>
using namespace std;
int main()
{
int n=0;//士兵的人数
int i=0,j=0;//循环变量
int count=0;//用于记录比当前士兵矮的士兵人数
int sum=0;//符合条件的士兵总数
cout<<"请输入士兵人数n(1<=n<=50000):"<<endl;
cin>>n;
while(n<1||n>50000)//检查士兵人数 n 是否合法
{
cout<<"输入n不符合要求!!!!!"<<endl;
cout<<"请重新输入士兵个数:(1<=n<=50000)"<<endl;
cin>>n;
}
long *H=new long[n+1];
for(i=0;i<=n;i++)//初始化分配的数组
H[i]=0;
cout<<"请输入的士兵身高H(1<=H<=2000000000):"<<endl;
for(i=1;i<=n;i++)
cin>>H[i];
for(i=1;i<=n;i++)//检查士兵的身高是否有
{ //小于1或是大于2000000000的数据
while(H[i]<1||H[i]>2000000000)
{
cout<<"输入的士兵身高不符合要求!!!"<<endl;
cout<<"输入的士兵身高中有小于1或是大于2000000000的数据!"<<endl;
cout<<"请重新输入 "<<n<<" 个士兵的身高:(1<=H<=2000000000)"<<endl;
for(j=1;j<=n;j++)
cin>>H[j];
}
}
for(i=1;i<=n;i++)//检查士兵的身高中是否有相等的数据
{
for(j=i+1;j<=n;j++)
{
if(H[i]==H[j])
{
cout<<"输入的士兵身高不符合要求!"<<endl;
cout<<"输入的士兵身高中有相等的数据!!!"<<endl;
cout<<"请重新输入 "<<n<<" 个士兵的身高:(1<=H<<2000000000)"<<endl;
for(j=1;j<=n;j++)
cin>>H[j];
break;
}
}
}
for(i=1;i<=n;i++)//进行比较
{
for(j=i+1;j<=n;j++)
{
if(H[i]<H[j])//如果右侧有比他高的,则结束本次比较
break;
count++;
}
sum+=count;
count=0;
}
cout<<sum<<endl;
delete[] H;
return 0;
}
25 楼
香脆饼干 [专家分:2040] 发布于 2007-03-23 12:46:00
这次代码经过精心提炼,绝对是最优化的。。。
#include <stdio.h>
int Height[50000];
int main()
{
int offset,sum,i;
scanf("%d",Height);
getchar();
for(i=1;i<=Height[0];i++)
scanf("%d",Height+i);
Height[i]=2000000001;
sum=0;
for(i=1;i<=Height[0];i++)
{
offset=1;
while(Height[i]>Height[i+offset++]);
offset-=2;
sum+=offset;
}
printf("%d",sum);
return 0;
}
26 楼
BigCarrot [专家分:10] 发布于 2007-03-23 13:11:00
//O(n) 的算法
// while循环实际执行的次数最多为n, 有兴趣的同学自己分析一下
#include <stdio.h>
#include <memory.h>
#define MAX 50004
static int h[MAX];
static int prev[MAX];
static int S[MAX];
int main()
{
memset(prev, 0, sizeof(prev));
memset(S, 0, sizeof(S));
int i,j;
int n;
int count = 0;
scanf("%d", &n);
h[0] = 2000000001;
for (i=1; i<=n; i++)
{
scanf("%d", &(h[i]));
j = i-1;
while (h[i] > h[j])
j = prev[j];
prev[i] = j;
}
for (i=n; i>0; i--)
{
count += S[i];
j = prev[i];
S[j] = S[j] + S[i] + 1;
}
printf("%d", count);
return 0;
}
27 楼
咖喱炒饭 [专家分:210] 发布于 2007-03-23 13:54:00
看看答案
28 楼
Kummerwu [专家分:0] 发布于 2007-03-23 14:08:00
#define MAX_SOLDIER_CNT 50000
#define MAX_SOLDIER_H 2000000000
typedef struct taller
{
int h; /* 第一个比自己高的士兵的身高 */
int pos; /* 该士兵的位置 */
}TALLER;
//说白了,就是一个出栈,入栈的过程,每个元素入栈一次,在入栈的过程中,
//可以将比自己小的元素踢出栈,所以最坏情况下,所有元素入栈,出栈各操作一次
//故复杂度为O(n)
int CountShort(int n, int * h)
{
int count = 0;
static TALLER talls[MAX_SOLDIER_CNT + 2]; //高个子俱乐部
TALLER * cur_tall = talls;
cur_tall->h = MAX_SOLDIER_H + 1; //标兵(靠,这家伙还真高呀)
cur_tall->pos = n;
for(n-=2;n>=0;n--)
{
//如果我比右侧的那个家伙高(俺也算个高个子了)
if(h[n]>h[n+1])
{
//把比自己矮的士兵踢出栈,(呵呵,爽! )
while(cur_tall->h < h[n])
{
cur_tall--; //这里可能有优化的空间??
}
//算算中间有几个矮冬瓜(现在cur_tall是第一个比我高的家伙)
count+=cur_tall->pos - n - 1;
//呵呵,俺光荣的加入高个子俱乐部了 :).
cur_tall++;
cur_tall->h = h[n];
cur_tall->pos = n;
}
//靠,右侧那家伙比我高
//(算了,让他进入高个子堆吧,反正也没啥油水可以捞)
else
{
cur_tall++;
cur_tall->h = h[n+1];
cur_tall->pos = n+1;
}
}
return count;
}
29 楼
hzlajx [专家分:1310] 发布于 2007-03-23 15:19:00
#include<iostream>
#include<stdlib.h>
using namespace std;
unsigned int CountHeight(int n,unsigned long *H) //函数的具体实现
{//1
unsigned int max[100]={0},next=0,count=0,i,j=0;
int m,sta;//重复次数
long temp;
for(i=1;i<n;i=max[j]+1)
{//2
loop:temp=H[max[j]]-H[i];
next=i+1;
// cout<<"##"<<endl; //*****************
if(temp<0) //交换接力棒
max[j]=i;
else if(temp>0) //传递比较大小
{//3
{
count++;
// cout<<count<<endl; //********************
}
m=1;
while(next<=n) //传递大小具体实现
{ //4
temp=H[i]-H[next];
// cout<<"**"<<endl; //***********************
if(temp<0)
{//5
// ***************************************
for(sta=j;sta>=0;sta--)
//****************************************
{
temp=H[max[sta]]-H[next];
m--; //取消累加
if(temp<0)
{max[sta]=next;m--;i++;goto loop;} //交换接力棒,退出循环
else if(temp>0)
{
i++;next++;j++; //后移比较
m++; //恢复原始
count+=m;
// cout<<count<<endl; //********************8
break;
} //
}
}//5
else if(temp>0)
{
i++;next++; //后移比较
m++; //进行累加
count+=m;
// cout<<count<<endl; //**********************
continue;
}
}//4
} //3
}//2
return count;
}
int main(void)
{
cout<<"请输入人数:"; //确定人数
int Num=0;
cin>>Num;
cout<<"请输入每位的身高:"<<endl; //输入身高
unsigned long Height[Num];
for(int i=0;i<Num;i++)
cin>>Height[i];
unsigned int count=0;
count=CountHeight(Num,Height); //函数接口统计数目
cout<<count<<endl;
system("pause");
return 0;
}
/******************************************************
我的算法就是让前一个数a[i]去减后面的一个数a[i+1],如果前面的比后面的大,就
让a[i+1]与a[i+2]比较,如果还是前面的大,就记录值+2,否则就记录+1,利用他们的
传递性,如果前一个总比后一个大,那么只需要扫描一遍,因为他的次数可以1+2+……+n
来计算。相反,如果在传递过程中发现后一个比前一个大,那么只需要和前面区间
的最大数比较就可以了,相应的记录值-1就可以了。
例如:
10 5 7 4 12 2
先定义最大为10,10-5 ——记录+1
然后 5-7<0 —— 10-7 ——记录+1
然后 7-4>0 ---- 记录+2
然后 4-12<0 ---- 7-12<0 ---10-12<0 ----记录+0 大于0跳出,小于0记录--
然后 12-2>0 ---- 记录+1 */
30 楼
huamao [专家分:0] 发布于 2007-03-23 15:29:00
#include<iostream>
using namespace std;
const int MaxCount = 50000; // 存放士兵身高数组的最大值
void main()
{
long SoldierHeight[MaxCount]; // 存放士兵身高的数组(2^31-1)
int SoldierCount; // 实际士兵个数
long i,j; // 循环变量
int Sum = 0; // 输出结果(计数器)
// 获得用户输入的值
cin >> SoldierCount;
for(i=0;i!=SoldierCount;++i)
{
cin >> SoldierHeight[i];
}
// 计算结果
for(i=0;i!=SoldierCount-1;++i)
{
long MaxHeight;
int nCount = 0; // 第i个士兵可看到右侧比他矮的士兵个数
for(j=i+1;j!=SoldierCount;++j)
{
MaxHeight = SoldierHeight[j];
if(MaxHeight > SoldierHeight[i])
{
break;
}
else
{
nCount++;
}
}
Sum = Sum + nCount;
}
cout << Sum << endl;
}
我来回复