您的位置:首页 > 其它

51Nod拉勾专业算法能力测评

2017-07-23 15:57 260 查看
**走格子**


基准时间限制:1 秒 空间限制:131072 KB 分值: 5

有编号1-n的n个格子,机器人从1号格子顺序向后走,一直走到n号格子,并需要从n号格子走出去。机器人有一个初始能量,每个格子对应一个整数A[i],表示这个格子的能量值。如果A[i] > 0,机器人走到这个格子能够获取A[i]个能量,如果A[i] < 0,走到这个格子需要消耗相应的能量,如果机器人的能量 < 0,就无法继续前进了。问机器人最少需要有多少初始能量,才能完成整个旅程。

例如:n = 5。{1,-2,-1,3,4} 最少需要2个初始能量,才能从1号走到5号格子。途中的能量变化如下3 1 0 3 7。

Input

第1行:1个数n,表示格子的数量。(1 <= n <= 50000)

第2 - n + 1行:每行1个数A[i],表示格子里的能量值(-1000000000 <= A[i] <= 1000000000)

Output

输出1个数,对应从1走到n最少需要多少初始能量。

Input示例

5

1

-2

-1

3

4

Output示例

2

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
long long int m,n,s=0,i;
long long int minn=0x3f3f3f3f;
scanf("%lld",&n);
for(i=0;i<n;i++)
{
scanf("%lld",&m);
s+=m;
if(s<minn)
minn=s;
}
if(minn>=0)
printf("0\n");
else
printf("%lld\n",0-minn);
return 0;
}


**扔盘子**


基准时间限制:1 秒 空间限制:131072 KB 分值: 10

有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。

盘子有几种命运:1、掉到井底。2、被卡住。3、落到别的盘子上方。

盘子的高度也是单位高度。给定井的宽度和每个盘子的宽度,求最终落到井内的盘子数量。

如图井和盘子信息如下:

井:5 6 4 3 6 2 3

盘子:2 3 5 2 4

最终有4个盘子落在井内。

本题由 @javaman 翻译。

Input

第1行:2个数N, M中间用空格分隔,N为井的深度,M为盘子的数量(1 <= N, M <= 50000)。

第2 - N + 1行,每行1个数,对应井的宽度Wi(1 <= Wi <= 10^9)。

第N + 2 - N + M + 1行,每行1个数,对应盘子的宽度Di(1 <= Di <= 10^9)

Output

输出最终落到井内的盘子数量。

Input示例

7 5

5

6

4

3

6

2

3

2

3

5

2

4

Output示例

4

这个题目正着来做肯定比较麻烦,可以试着简化一下

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
int i,j;
int a[50005],b[50005];
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<m;i++)
scanf("%d",&b[i]);
for(i=1;i<n;i++)
a[i]=min(a[i-1],a[i]);//从井口向下进行初始化,只有上面的横截面积比下面的横截面积大才有意义
int count=0;
for(i=0;i<m;i++)
{
for(n--;n>=0;n--)//当前盘子可以卡住的话数目加1,继续判断下一个盘子情况
{
if(a
>=b[i])
break;
}
if(n>=0)
count++;
}
printf("%d\n",count);
return 0;
}


**独木舟**


基准时间限制:1 秒 空间限制:131072 KB 分值: 10

n个人,已知每个人体重。独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人。显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟?

Input

第一行包含两个正整数n (0

首先将人的体重升序排列,再从两头一起开始判断
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
int a[10005],b[10005],i,j;
memset(b,0,sizeof(b));
scanf("%d %d",&n,&m);
int k=n-1,sum=0;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(i=0;i<=k;i++)
{
int flag=0;
if(b[i]==0)
{
for(j=k;j>=i;j--)
if(b[j]==0&&a[i]+a[j]<=m)
{
sum++;
b[i]=1;
b[j]=1;
flag=1;
//k=j-1;
break;
}
if(flag==0)
{
b[i]=1;
sum++;
}
}
}
printf("%d\n",sum);
return 0;
}


**斜率最大**


基准时间限制:1 秒 空间限制:131072 KB 分值: 20

平面上有N个点,任意2个点确定一条直线,求出所有这些直线中,斜率最大的那条直线所通过的两个点。

(点的编号为1-N,如果有多条直线斜率相等,则输出所有结果,按照点的X轴坐标排序,正序输出。数据中所有点的X轴坐标均不相等,且点坐标为随机。)

Input

第1行,一个数N,N为点的数量。(2 <= N <= 10000)

第2 - N + 1行:具体N个点的坐标,X Y均为整数(-10^9 <= X,Y <= 10^9)

Output

每行2个数,中间用空格分隔。分别是起点编号和终点编号(起点的X轴坐标 < 终点的X轴坐标)

Input示例

5

1 2

6 8

4 4

5 4

2 3

Output示例

4 2

刚开始是用常规方法做,当然时间超了

后来才知道可以用数学结论节省时间

先把这些点按x坐标从小到大排序,斜率最大的两点必然是挨一起的两个点,所以排序O(n* lg n),遍历一次O(n)就够了

详细解释看这里

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int x;
int y;
int z;
double d;
};
int cmp(node a,node b)
{
a.x<b.x;
}
int main()
{
int n;
int i,j;
double t;
node a[10005],d;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i].x,&a[i].y);
a[i].z=i;
}
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
{
if(a[i].x>a[j].x)
{
d.x=a[i].x;
d.y=a[i].y;
d.z=a[i].z;
a[i].x=a[j].x;
a[i].y=a[j].y;
a[i].z=a[j].z;
a[j].x=d.x;
a[j].y=d.y;
a[j].z=d.z;
}
}
double maxn=-0x3f3f3f3f;
for(i=0;i<n-1;i++)
{
if(a[i].x!=a[i+1].x)
{
double t=(a[i+1].y-a[i].y)*1.0/(a[i+1].x-a[i].x);
a[i].d=t;
if(maxn<t)
maxn=t;
}
}
for(i=0;i<n-1;i++)
{
if(maxn==a[i].d)
{
printf("%d %d\n",a[i].z+1,a[i+1].z+1);
}
}
return 0;
}


数据流中的算法

基准时间限制:1.5 秒 空间限制:131072 KB 分值: 20

51nod近日上线了用户满意度检测工具,使用高级人工智能算法,通过用户访问时间、鼠标轨迹等特征计算用户对于网站的满意程度。

现有的统计工具只能统计某一个窗口中,用户的满意程度的均值。夹克老爷想让你为统计工具添加一个新feature,即在统计均值的同时,计算窗口中满意程度的标准差和中位数(均值需要向下取整)。

Input

第一行是整数n与k,代表有n次操作,时间窗口大小为k。

(1 <= n <= 10^6, 1 <= k <= 100)

接下来的n行,每行代表一次操作。操作有“用户访问”、“查询均值”、“查询方差”、“查询中位数”四种。每行的第一个数代表操作类型。

操作数1:用户访问

输入格式:<1, v>

用户的满意度v为闭区间[0, 100]中的任意整数。用户每访问一次,数据更新,移动统计窗口。

操作数2:查询均值

输入格式:<2>

统计窗口内的用户满意度的均值。

操作数3:查询方差

输入格式:<3>

统计窗口内用户满意度的方差

操作数4:查询中位数

输入格式:<4>

统计窗口内用户满意度的中位数

p.s. 在有查询请求时,窗口保证不为空

p.s.s. 有查询请求时,窗口可能不满

Output

对于“查询均值”、“查询方差”、“查询中位数”操作的结果,输出保留两位小数。

Input示例

12 3

1 1

1 2

1 3

2

3

4

1 4

1 5

1 6

2

3

4

Output示例

2.00

0.67

2.00

5.00

0.67

5.00

k的用处题目描述的不清楚,可以理解为该统计工具所能保存的数据个数

比较复杂的一道模拟题

特别是求中位数时容易超时,由于满意度的取值范围不大,用户的满意度v为闭区间[0, 100]中的任意整数,所以可用一个稍大于100数组来存放用户的满意度,就可避免超时

#include<stdio.h>
#include<string.h>
int main()
{
int n,k,now;
int i,j,a[105],ss[105];
scanf("%d %d",&n,&k);
for(i=0;i<k;i++)
a[i]=-1;
char s[10];
int ii=-1;
getchar();
now=0;
for(i=0;i<=100;i++)
ss[i]=0;
for(int iii=0;iii<n;iii++)
{
//printf("iii:%d\n",iii);
gets(s);
int t=0;
if(s[0]=='1')
{
int len=strlen(s);
for(i=2;i<len;i++)
if(s[i]>='0'&&s[i]<='9')
t=t*10+s[i]-'0';
ii++;
ss[a[ii%k]]--;
a[ii%k]=t;
ss[a[ii%k]]++;
if(ii<k)
now++;
}
else if(s[0]=='2')
{
int sum=0;
int tt=0;
for(i=0;i<k;i++)
{
if(a[i]!=-1)
{
tt++;
sum+=a[i];
}
}
if(tt!=0)
{
int su=sum/tt;
sum=su;
printf("%d.00\n",su);
}
}
else if(s[0]=='3')
{
double sum=0,s=0;
int tt=0;
for(int i=0;i<k;i++)
{
if(a[i]!=-1)
{
tt++;
sum+=a[i];
}
}
if(tt!=0)
sum=sum*1.0/tt;
for(int i=0;i<k;i++)
{
if(a[i]!=-1)
s+=(a[i]-sum)*(a[i]-sum);
}
s=s/tt;
printf("%.2lf\n",s);
}
else if(s[0]=='4')
{
int flag=0,tlag;
int ttt;
if(now%2!=0)
{
ttt=-1;
for(int kk=0;kk<=100;kk++)
{
if(flag==0)
{
ttt+=ss[kk];//printf("ttt:%d\n",ttt);
if(ttt>=now/2)
{
printf("%.2lf\n",(double)kk);
flag=1;
}
}
}
}
else
{
int st,ed;
int rlag=0;
tlag=0,flag=0;
ttt=-1;
for(int kk=0;kk<=100;kk++)
{
//printf("ss[%d]:%d\n",kk,ss[kk]);
if(tlag==0||flag==0)
{
ttt+=ss[kk];//printf("ttt:%d\n",ttt);
if(ttt>=now/2-1&&tlag==0)
{
st=kk;
tlag=1;
}
if(ttt>=now/2&&flag==0)
{
ed=kk;
flag=1;
}
}
if(tlag==1&&flag==1&&rlag==0)
{
printf("%.2lf\n",(double)(st+ed)/2);
rlag=1;
}
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: