【JLU数据结构荣誉课】第一次上机实验
->点我进原题
-> 7-1 重复计数
-> 7-2 报数游戏
-> 7-3 算术表达式计算
-> 7-4 最喜爱的序列
7-1 重复计数 (100 分)
代码长度限制 \(16 KB\)
时间限制 \(1000 ms\)
内存限制 \(64 MB\)
Description
在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。
Input
第1行,1个整数 \(N\) ,表示整数的个数,\((1≤N≤50000)\)。
第2行,\(N\) 个正整数,每个整数 \(x\) 都满足 \(1 ≤ x ≤2000000000\)。
Output
若干行,每行两个用一个空格隔开的数,第一个是数列中出现的数,第二个是该数在序列中出现的次数。
Sample Input
12
8 2 8 2 2 11 1 1 8 1 13 13
Sample Output
8 3
2 3
11 1
1 3
13 2
思路
map裸题,将出现多少个数用 \(tot\) 和 \(b\) 数组记录有多少个数出现,用map记录每个数出现的次数即可。
代码
#include<cstdio>
#include<cctype>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define rg register
#define ll long long
using namespace std;
inline ll read(){
rg ll f = 0, x = 0;
rg char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f? -x: x;
}
ll b[50010];
int tot = 0;
map <int, int> mp;
int main(){
ll n = read();
ll a[50010];
for(rg int i = 1; i <= n; ++i){
ll tmp = read();
if(!mp[tmp]){
b[++tot] = tmp;
mp[tmp]++;
} else mp[tmp]++;
}
for(rg int i = 1; i <= tot; ++i){
printf("%lld %lld\n", b[i], mp[b[i]]);
}
return 0;
}
7-2 报数游戏 (100 分)
代码长度限制 \(16 KB\)
时间限制 \(400 ms\)
内存限制 \(64 MB\)
Description
\(n\) 个人围成一圈,从 \(1\) 开始依次编号,做报数游戏。 现指定从第 \(1\) 个人开始报数,报数到第 \(m\) 个人时,该人出圈,然后从其下一个人重新开始报数,仍是报数到第 \(m\) 个人出圈,如此重复下去,直到所有人都出圈。总人数不足 \(m\) 时将循环报数。请输出所有人出圈的顺序。
Input
一行,两个整数 \(n\) 和 \(m\) 。\(n\) 表示游戏的人数,\(m\) 表示报数出圈的数字,\(1≤n≤50000\),\(1≤m≤100\).
Output
一行,\(n\) 个用空格分隔的整数,表示所有人出圈的顺序
Sample Input
5 2
Sample Output
2 4 1 5 3
思路
经典约瑟夫问题,不多解释
代码
#include<cstdio>
#include<cctype>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define rg register
#define ll long long
using namespace std;
inline int read(){
rg int f = 0, x = 0;
rg char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f? -x: x;
}
int main(){
int n = read(), m = read();
int a[50010] = {0}, cnt = n, ind = 1, num = 1;
while(cnt){
if(ind == n + 1) ind = 1;
if(a[ind]){
ind ++;
continue;
}
if(num == m){
a[ind] = 1;
printf("%d", ind);
num = 1;
cnt --;
if(cnt) printf(" ");
}
else{
num ++;
}
ind ++;
}
return 0;
}
7-3 算术表达式计算 (100 分)
代码长度限制 \(16 KB\)
时间限制 \(400 ms\)
内存限制 \(64 MB\)
Description
任务: 计算算术表达式的值。
算术表达式按中缀给出,以 \(=\) 号结束,包括 \(+,-,\times,\div\) 四种运算和 \((\)、\()\) 分隔符。运算数的范围是非负整数,没有正负符号,小于等于 \(10^{9}\)。
计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。 输入保证表达式正确。
Input
一行,包括1个算术表达式。算术表达式的长度小于等于 \(1000\)。
Output
一行,算术表达式的值 。
Sample Input
(1+30)/3=
Sample Output
10
思路
用一个栈来存符号,另一个栈来存数字。如果是数字直接入数字栈;如果是符号,栈空则立刻入栈,是左括号立刻入栈,优先级大于上一个字符入栈,是右括号则一直弹栈运算到弹出左括号,如果优先级小于等于上一个字符,则一直运算弹栈到左括号或栈空。要特别注意优先级的判断与不合法情况的判断(除数不为0)。详情见代码。
代码
#include<cstdio>
#include<cctype>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
inline bool judpri(char a, char b){
if((a == '*' || a == '/') && (b == '+' || b == '-')) return 1;
if((a == '+' || a == '-') && (b == '+' || b == '-')) return 0;
if((a == '+' || a == '-') && (b == '*' || b == '/')) return 0;
if((a == '*' || a == '/') && (b == '*' || b == '/')) return 0;
return 1;
}
inline int cal(int n1, char opt, int n2){
if(opt == '+') return n1 + n2;
if(opt == '-') return n1 - n2;
if(opt == '*') return n1 * n2;
if(opt == '/') return n1 / n2;
}
inline bool judcal(char opt, int num){
if(opt == '/' && num == 0) return 0;
else return 1;
}
int main(){
char ch;
int Q[10100];//num
int qtop = 0;
char C[10100];//opt
int ctop = 0;
int book = 0;
scanf("%c", &ch);
if(ch == '=') book = 1;
// cout << ch<<endl;
while(!book){
// cout << ch << endl;
int num[20], tot = 0;
int sum = 0;
while(ch >= '0' && ch <= '9'){
// cout << ch<<endl;
num[++ tot] = ch - '0';
scanf("%c", &ch);
if(ch == '=') book = 1;
}
if(tot){
for(int i = 1; i <= tot; ++i){
sum = sum * 10 + num[i];
}
Q[++qtop] = sum;
// cout << sum << endl;
continue;
}
// cout << ch << endl;
if(ch == ')'){
while(C[ctop] != '(' && ctop){
int n2 = Q[qtop --], c = C[ctop --], n1 = Q[qtop --];
// cout << n1 << ' ' << c << ' ' << n2 << endl;
if(!judcal(c, n2)){
printf("NaN");
return 0;
}
int ans = cal(n1, c, n2);
Q[++qtop] = ans;
}
ctop --;
} else if(ch == '(' || !ctop || judpri(ch, C[ctop])){
C[++ctop] = ch;
// putchar(ch);
} else{
while(ctop && C[ctop] != '('){
int n2 = Q[qtop --], c = C[ctop], n1 = Q[qtop --];
// cout << n1 << ' ' << c << ' ' << n2 << endl;
if(!judcal(c, n2)){
printf("NaN");
return 0;
}
int ans = cal(n1, c, n2);
Q[++qtop] = ans;
ctop --;
}
C[++ctop] = ch;
}
scanf("%c", &ch);
if(ch == '=') book = 1;
// cout << ch<<endl;
}
while(ctop){
int n2 = Q[qtop --], c = C[ctop], n1 = Q[qtop --];
if(!judcal(c, n2)){
printf("NaN");
return 0;
}
int ans = cal(n1, c, n2);
Q[++qtop] = ans;
ctop --;
}
printf("%d", Q[1]);
return 0;
}
//(((1+2)/(1+1-1)/3)*2/2/2)+1)+1=
7-4 最喜爱的序列 (100 分)
代码长度限制 \(16 KB\)
时间限制 \(400 ms\)
内存限制 \(64 MB\)
Description
小唐这段时间在研究序列。拿来 \(n\) 个整数的序列,他给序列中的每个整数都赋予一个喜爱值。喜爱值也是整数,有正有负,越大表明越喜欢。他想知道,如何从序列中连续取最多 \(m\) 个数,他获得喜爱值最大。\(1≤n≤500000\),\(1≤m≤N\)。
Input
第一行是两个整数 \(n\), \(m\) 。分别代表序列中数的个数以及能取的最多个数。
第二行用空格隔开的 \(n\) 个整数,第 \(i\) 个整数 \(Li\) 代表他对第 \(i\) 个数的喜爱值。\(│Li│≤1000\)
Output
一行,三个数,表示获得最大喜爱值,及第一个取最大喜爱值的区间。
Sample Input
5 2
1 4 5 2 3
Sample Output
9 2 3
思路
单调队列。处理一个前缀和,单调队列中存左端点,保持从1到左端点的和单调递增,当超过区间距离时出队,每次以队头点到当前端点的区间和与答案比较,更新答案即可。
代码
#include<cstdio>
#include<cctype>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define rg register
#define ll long long
using namespace std;
inline int read(){
rg int f = 0, x = 0;
rg char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f? -x: x;
}
const int inf = 0x7fffffff;
int q[500010], maxn, ml, mr;
int sum[500010];
int main(){
int n = read(), m = read();
sum[0] = 0;
int f = 0, r = -1;
maxn = -inf;
for(rg int i = 1; i <= n; ++i){
sum[i] = sum[i - 1] + read();
}
for(rg int i = 1; i <= n; ++i){
while(f <= r && q[f] < i - m) f++;
if(maxn < sum[i] - sum[q[f]]){
maxn = sum[i] - sum[q[f]];
ml = q[f] + 1;
mr = i;
}
while(f <= r && sum[q[r]] >= sum[i]) r--;
q[++r] = i;
}
printf("%d %d %d", maxn, ml, mr);
return 0;
}