呜呜呜,本来是想进入荣誉课学习更好的知识,没想到这么难,但作为一个编程小白,也希望让自己的能力更强。。。
本文部分代码和思想借鉴于网络大佬。
7-1 数列查询
分数 100
全屏浏览题目
切换布局
作者 谷方明
单位 吉林大学
已知数列的通项公式为:
f(n) = f(n-1)*11/10,f[1]=10.
通项从左向右计算,*和/分别表示整数乘法和除法。
现在,要多次查询数列项的值。
第1行,1个整数q,表示查询的次数, 1≤q≤10000.
第2至q+1行,每行1个整数i,表示要查询f(i)的值。
q行,每行1个整数,表示f(i)的值。查询的值都在32位整数范围内。
在这里给出一组输入。例如:
3
1
2
3
在这里给出相应的输出。例如:
10
11
12
代码长度限制
16 KB
时间限制
10 ms
内存限制
1 MB
这题比较简单,作为没有数据结构和算法基础的小白,我先想的是能用数组解决,绝不用递归(时间限制),因为假期看了一些排序方面的知识,我私以为桶排序的思想是最简单的(个人想法,可能不对),就是把一些输入的东西用另一个数组存起来就好了,方便后面的进行,上代码:
#include
long long a[10001];
int b[10001];
int main() {
a[1]=10;
for(int i=2; i<=10001; i++) {
a[i]=a[i-1]*11/10;
}
int n; scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&b[i]);
}
for(int i=1; i<=n; i++) {
printf("%lld\n",a[b[i]]);
}
return 0;
}
时间复杂度:O(n).
空间复杂度:O(n).
7-2 报数游戏
分数 100
全屏浏览题目
切换布局
作者 谷方明
单位 吉林大学
n个人围成一圈,从1开始依次编号,做报数游戏。 现指定从第1个人开始报数,报数到第m个人时,该人出圈,然后从其下一个人重新开始报数,仍是报数到第m个人出圈,如此重复下去,直到所有人都出圈。总人数不足m时将循环报数。请输出所有人出圈的顺序。
一行,两个整数n和m。n表示游戏的人数,m表示报数出圈的数字,1≤n≤50000,1≤m≤100.
一行,n个用空格分隔的整数,表示所有人出圈的顺序
在这里给出一组输入。例如:
5 2
在这里给出相应的输出。例如:
2 4 1 5 3
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
用一个数组来存放 1,2,3 ... n 这 n 个编号,如图(这里我们假设n = 6, m = 3)
然后不停着遍历数组,对于被选中的编号,我们就做一个标记,例如编号 arr[2] = 3 被选中了,那么我们可以做一个标记,例如让 arr[2] = -1,来表示 arr[2] 存放的编号已经出局的了。
然后就按照这种方法,不停着遍历数组,不停着做标记,直到数组中只有一个元素是非 -1 的,这样,剩下的那个元素就是我们要找的元素了。(借鉴一下网图,这是后来复盘后,网络大佬其中的一个方法,)
但我是没有将数组的序号更新,而是另设了一个标志数组来储存。(思想差不多)。
上代码:
#include
int a[50001];
int b[50001];
int c[50001];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
a[i]=i;
}
int top=0;
int j=1;
for(int i=1; i<=n;) {
if(c[i]==1) {
} else {
top++;
}
if(top==m) {//top到达数值则更新
top=0;
b[j]=a[i];
c[i]=1;//标志数组
j++;
}
if(i==n) {
i=0;//循环
}
i++;
if(j==n+1)break;//容易卡人,真是要判断好临界条件。
}
for(int i=1; i<=n; i++) {
if(i==n)printf("%d",b[i]);
else {
printf("%d ",b[i]);
}
}
return 0;
}
约瑟夫问题:有 N 个人围成一圈,每个人都有一个编号,编号由入圈的顺序决定,第一个入圈的人编号为 1,最后一个为 N,从第 k (1<=k<=N)个人开始报数,数到 m (1<=m<=N)的人将出圈,然后下一个人继续从 1 开始报数,直至所有人全部出圈,求依次出圈的编号。
暂介绍三种方法(实力有限):
3.7-3 算术表达式计算
分数 100
全屏浏览题目
切换布局
作者 谷方明
单位 吉林大学
任务: 计算算术表达式的值。
算术表达式按中缀给出,以=号结束,包括+,-,,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109 。
计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。
输入保证表达式正确。
一行,包括1个算术表达式。算术表达式的长度小于等于1000。
一行,算术表达式的值 。
在这里给出一组输入。例如:
(1+30)/3=
在这里给出相应的输出。例如:
10
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
这题说实话我看到的时候直接跳了,因为我知道自己写不出来,就是平时理论没有付诸实践,到不得不用数据结构的时候就懵了。
两个栈分别存数字字符和符号字符,算法就是老师上课讲的,主要是一动手就不知道咋干了。
上代码:
#include
#include
#include
#include
#include
using namespace std;
int main(){
std::stack
std::stack
int i,j=0,k=0,l,sum1,sum2;
char s[1010],m;
scanf("%s",s);
l=strlen(s);
for(i=0;i
if(s[i]>='0'&&s[i]<='9'){
j=j*10+s[i]-'0';
k=1; //做标志来判断后续的是否还为数字
}
else{
if(k){
p.push(j);
k=0;j=0;
}
if(q.empty())
{q.push(s[i]); //压入符号
continue ;
}
m=q.top();
switch(s[i]){
case '+':
case '-':if(m=='+'||m=='-'||m=='*'||m=='/'){ //如果压入+或-则将前边的优先级低的计算
sum2=p.top();p.pop();sum1=p.top();p.pop();
if(m=='+')
p.push(sum1+sum2);
if(m=='-')
p.push(sum1-sum2);
if(m=='/')
{
if(sum2==0)
{printf("NaN");
exit(0);}
p.push(sum1/sum2);
}
if(m=='*')
p.push(sum1*sum2);
q.pop();
}
q.push(s[i]);break;
case '*':
case '/':if(m=='*'||m=='/'){
sum2=p.top();p.pop();sum1=p.top();p.pop();
if(m=='/')
{
if(sum2==0)
{printf("NaN");
exit(0);}
p.push(sum1/sum2);
}
if(m=='*')
p.push(sum1*sum2);
q.pop();
}
q.push(s[i]);break;
case '(':q.push(s[i]);break;//左括号则将其视为一个新的表达式重新计算
case ')':while(q.top()!='('){//右括号则将标志着这个表达式计算完毕弹栈直到遇到左括号
m=q.top();
if(m=='+'||m=='-'||m=='*'||m=='/'){
sum2=p.top();p.pop();sum1=p.top();p.pop();
if(m=='+')
p.push(sum1+sum2);
if(m=='-')
p.push(sum1-sum2);
if(m=='/')
{
if(sum2==0)
{printf("NaN");
exit(0);}
p.push(sum1/sum2);
}
if(m=='*')
p.push(sum1*sum2);
q.pop();
}
} q.pop();break;
}
}
}
while(!q.empty()){//将剩余的数值和符号计算完毕
m=q.top();
if(m=='+'||m=='-'||m=='*'||m=='/'){
sum2=p.top();p.pop();sum1=p.top();p.pop();
if(m=='+')
p.push(sum1+sum2);
if(m=='-')
p.push(sum1-sum2);
if(m=='/')
{
if(sum2==0)
{printf("NaN");
exit(0);}
p.push(sum1/sum2);
}
if(m=='*')
p.push(sum1*sum2);
q.pop();
}
}
printf("%d",p.top());
return 0;
}
时间复杂度(O(n));
空间复杂度(O(n));
7-4 最喜爱的序列
分数 100
全屏浏览题目
切换布局
作者 谷方明
单位 吉林大学
小唐这段时间在研究序列。拿来N个整数的序列,他给序列中的每个整数都赋予一个喜爱值。喜爱值也是整数,有正有负,越大表明越喜欢。他想知道,如何从序列中连续取最多m个数,他获得喜爱值最大。1≤N≤500000,1≤m≤N。
第一行是两个整数N,m。分别代表序列中数的个数以及能取的最多个数。
第二行用空格隔开的N个整数,第i个整数Li代表他对第i个数的喜爱值。│Li│≤1000
一行,三个数,表示获得最大喜爱值,及第一个取最大喜爱值的区间。
在这里给出一组输入。例如:
5 2
1 4 5 2 3
在这里给出相应的输出。例如:
9 2 3
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
这题我看的时候感觉有点小稳,因为老师之前发的练习题我不会,去问唐班大佬,了解到了前缀和,但编程小白的不足在这道题还是显得淋漓尽致,不会单调队列。。。我一开始没好好读题,以为是只拿m个,写的很自信,但有一个点死活不过,但后来发现的时候已经下课了。。。
还有我这个算法小白真的要好好学习c++的STL,各种算法太方便了太快了。
上代码(在网上搜集到比较简便的算法):
#include
#include
#include
using namespace std;
int a[500010];
int main() {
std::deque
int m, n,i,j,k,l,l0,r,max=0xffffffff;//max设置为一个最小值为负值
scanf("%d%d", &n, &m);
q.push_back(0);//先押入一个0注意我们压入的是前缀和数组的下标0代表的是下标由于a[0]=0;所以我们压入这个数字并不会对结果造成影响。
for (i = 1;i <= n;i++)
{
scanf("%d", &a[i]);
a[i] += a[i - 1]; //将起转换为前缀和
k = a[i] - a[q.front()]; //计算这段区间内的最大值
if (k > max) {
l0 = q.front();r = i;max = k;
}
while (!q.empty()) {//对区间进行维护
l = q.back();
if (i - q.front() == m)
{
q.pop_front(); continue;
}
if (a[l] > a[i])
q.pop_back();
else
break;
}
q.push_back(i);
}
printf("%d %d %d", max, l0+1, r);
}
时间复杂度:O(n);(另一种方法再为m遍历建立一个数组发现爆了,n方好像就不行了)。
空间复杂度:O(n).