2019年2月17日训练日记

今天写几个题目:

过河
(对规律的把握)
有 n 个人来到了一条河的一边,他们都想到河的另一边。河的宽度为 k 米。不幸
的是,河边只有一条船(在他们所在的一边),容量为 m 人。他们要划船过河,
使所有人都到河的另一边。假设所有人都会划船,请问船最少经过的路程是多少
米,才能使所有人到达河的另一边?
数据范围:
1<=n<=1e9,2<=m<=1e9,1<=k<=1e9
输入
三个数,n,m,k,含义如上所述,每个数之间以一个空格隔开。
输出
船经过的最少路程,使所有人都到河的另一边。
样例
input

1 2 3

output

3

例程:
首先,注意到如果 n<=m,只需要一次即可将所有人运到河的对岸,那么船的路程
显然为 k。否则,第一次运输之后,必须留下至少一个人再将船划回对岸。也就是
说,除了第一次划船可以运送 m 个人到对岸以外,剩下的每一次运输(一个来
回)都只能运送 m-1 人到达对岸(第一次的第 m 个人划船,因为最终他是到达对
岸的)。也可以想象成每次运 m-1 人,当未到达对岸的人加上划船的人<=m 人,
就可以一次运过去了。注意船的来回之间的路程需要*2。然后就是注意精度会爆
int,需要用 long long。
这种做法效率很高,时间复杂度为 O(1)。有的同学运用了复杂的过程模拟,也可
以满分通过本题,不过效率较低。

 #include<bits/stdc++.h>
 #define ll long long
 using namespace std;
 int main()
 {
 int n,m,k,ans;
 scanf("%d%d%d",&n,&m,&k);
 if(n<=m) printf("%d\n",k);
 else {
 n-=m;
 ans=((n-1)/(m-1)+1);
 ans=ans*2+1;
 printf("%lld\n",(ll)ans*k);
 }
 }

准时的外卖?五星好评!
(对时间差的计算)
众所周知,ACM 集训队是一个外卖集训队,在这里你可以订各种各样的外卖,订外卖之余也可以抽时间打一下 ACM 比赛啥的,非常的惬意…… 而作为集训队最爱订外卖和最有原则的 LSD 学长,对于外卖的评价非常的偏执,不论味道和价格,他给外卖评分的准则就是是否能按时送到,如果在下单 1 小时 17 分钟以内(包括 1 小时 17 分钟时)送到,那么 LSD 学长就会给出五星好评,否则,晚一分钟,他便会减少一颗星,直到一星为止。
最近你知道了这两天 LSD 学长订外卖的时间和送到的时间,你能靠这些数据算出 LSD 学长每天打出
的评分吗?
输入:
第一行一个 D(1<=D<=100),代表 LSD 学长最近 D 天订外卖的情况;
以下有 D 组数据,每组两行,分别代表了下单时间 t1 与送到时间 t2;
时间采用 24 小时制,用 HH:MM 表示,HH 代表小时,MM 代表分钟,如果数字小于 10 则用前导
零填充(比如六点三分表示为 06:03)。
保证送到时间不小于下单时间,保证送到时间与下单时间是同一天内。
输出:
每组数据输出一行,每行有几个“*”(不加引号),代表 LSD 学长对于这次外卖给出了几星评价(每行
输出结尾没有多余空格)。
样例输入:

5
09:00
10:16
09:00
10:17
09:00
10:18
09:00
10:19
09:00
10:50

样例输出:

*****
*****
****
***

*小提示:
第一天外卖 9 点整下单,10 点 16 送到,共花费 1 小时 16 分钟,学长打出了”*****”;

第三天外卖 9 点整下单,10 点 18 送到,共花费 1 小时 18 分钟,学长打出了”****”;

第五天外卖 9 点整下单,10 点 50 送到,共花费 1 小时 50 分钟,学长打出了”*”;
字符”0”的 ascii 码是 48,将字符型的变量赋值给整数型的变量会传递 ascii 码的数值
题解:
这道题没有什么思维性,只需要读懂题意,按照题目要求写代码即可,主要考察代码能力,具体的实现方法见第三页代码。
标程:

#include <bits/stdc++.h>
using namespace std;
char t1[10],t2[10]; //定义两个字符串来存储时间
int main()
{
int D;
cin>>D;
while(D--)
{
for(int i=0;i<5;i++)
{
cin>>t1[i];
t1[i]-='0';
}
for(int i=0;i<5;i++)
{
cin>>t2[i];
t2[i]-='0';
}
/*以上都是输入,也可以使用 scanf(“%d:%d”,&a,&b)来进行输入*/
int time1,time2,time3;
time1=(t1[0]*10+t1[1])*60+(t1[3]*10+t1[4]);
time2=(t2[0]*10+t2[1])*60+(t2[3]*10+t2[4]);
time3=time2-time1;//计算时间差
if(time3<=77)
{
cout<<"*****"<<endl;//此情况五星
}
else //这里用多次的分支语句判断亦可以
{
int n;
n=5-(time3-77);
cout<<"*";
for(int i=0;i<n-1;i++)
{
cout<<"*";//根据时间打星,记得最少一颗星!
}
cout<<endl;
}
}
}

简单的数学题 解题报告
这是一道简单的数学题。给你一个数 n,求
在这里插入图片描述

数据范围:1<=n<=1000000
注意:本题的时限只有 2ms!!!
tips:
在这里插入图片描述
输入
一个数 n
输出
如上所述
样例
input

1

output

1

例程:
80 分的做法:
由于 C/C++中整数除法默认的就是向下取整,所以直接 for 累加一遍 n/i 的和就
行。但是此解法效率较低,复杂度为 O(n)。
代码:

#include<bits/stdc++.h>
using namespace std;
long long n,m,k,ans;
int main()
{
ans=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
ans+=n/i;
 printf("%lld\n",ans);
 }

100 分的做法:
除法有一个性质,就是对于每个 n,每个 i(1<=i<=n),值为 n/i(向下取整)的有
(n/(n/i))-i+1(都是向下取整)个。所以一次可以跳(n/(n/i))-i+1 个。称此方法为
除法分块,效率要比上面高很多,复杂度为 O(sqrt(n))。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
ll n,k,s,ans=0;
scanf("%lld",&n);
for(ll i=1;i<=n;i=s+1)
{
 k=n/i; 
 s=n/k; 
 ans+=(s-i+1)*k; 
 } 
 printf("%lld\n",ans); 
 }

这道题是暴力
给定一个整数序列,求此整数序列中最大连续子序列和(子序列长度可以为0)
例如:
给定 Arr = {-1, 2, 3, -4, 5, -6} ,则此序列的最大连续子序列和为: 6 ,即: {2, 3, -4, 5}
输入
第一行为一个整数 n,表示此序列中的元素个数后面 n 行为序列中的元素
n 的数据范围:90%, (0, 100]
10%, [1e5,1e5]
每个元素: [-100, 100]
输出
输出最大连续子序列和
样例
input

6
-1
2
3
-4
5
-6

output

6

例程:
90%的数据:(利用两个for循环枚举其子序列即可)
此题若使用暴力,可得90分,
暴力的时间复杂度达到了O(n^2),对于最后一个1e5的数据,即到达了1e10的规模,会导致超时(1e9就有可能超时)
100%数据:(dp,最大连续子段和,经典dp,自行百度即可-

#include <iostream>
using namespace std;
int main()
{
int n = 0;
cin>>n;
int sum = 0, res = 0;
for(int i = 0; i<n; i++)
{
int tmp;
cin>>tmp;
if(sum < 0)
{
sum = 0;
}
sum += tmp;
if(sum > res)
{
res = sum;
}
}
cout << (res < 0 ? 0 : res) << endl;
return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42785226/article/details/87557894