7-1 重复计数 (100 分)
在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。
输入格式:
第1行,1个整数N,表示整数的个数,(1≤N≤50000)。
第2行,N个正整数,每个整数x 都满足 1 ≤ x ≤2000000000。
输出格式:
若干行,每行两个用一个空格隔开的数,第一个是数列中出现的数,第二个是该数在序列中出现的次数。
输入样例:
在这里给出一组输入。例如:
12
8 2 8 2 2 11 1 1 8 1 13 13
输出样例:
在这里给出相应的输出。例如:
8 3
2 3
11 1
1 3
13 2
题目分析
直接用权值数组即可,pintia上虽可运行,学校的平台却会编译错误。
代码实现如下
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
int a[2000000000];
long j[50000],tem;
bool visited[2000000000]={false};
int main(){
int i,N;
scanf("%d",&N);
for(i=0;i<N;i++){
scanf("%ld",&j[i]);
visited[j[i]]=true;
a[j[i]]++;
}
for(i=0;i<N;i++){
if(visited[j[i]]){
printf("%ld %d\n",j[i],a[j[i]]);
visited[j[i]]=false;
}
}
return 0;
}
所以应用map和vector优化,map用来快速查询新读入的数是否被记录过并储存次序,vector存储出现次数。
代码实现如下
#include<iostream>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
vector<pair<int,int> > list;
map<int,int> tofind;
int n,i,k,t=0;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&k);
auto p=tofind.find(k);
if(p==tofind.end()){
tofind.insert(pair<int,int>(k,t));
list.push_back(pair<int,int>(k,1));
t++;
}
else{
list[p->second].second+=1;
}
}
for(i=0;i<list.size();i++){
printf("%d %d\n",list[i].first,list[i].second);
}
}
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
题目分析
经典的约瑟夫问题,由于机房的电脑一new就炸,所以用数组模拟循环链表。
代码实现如下
#include<stdio.h>
int next[50010];
int main(){
int n,m,i=0,die=1,r;
scanf("%d%d",&n,&m);
r=n;
for(i=1;i<n;i++){
next[i]=i+1;
}
next[i]=1;
while(n){
for(i=1;i<m;i++){
r=die;
die=next[die];
}
printf("%d",die);
if(n!=1)printf(" ");
next[r]=next[die];
next[die]=0;
die=next[r];
n--;
}
return 0;
}
7-3 算术表达式计算 (100 分)
任务: 计算算术表达式的值。
算术表达式按中缀给出,以=号结束,包括+,-,,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109 。
计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。 输入保证表达式正确。
输入格式:
一行,包括1个算术表达式。算术表达式的长度小于等于1000。
输出格式:
一行,算术表达式的值 。
输入样例:
在这里给出一组输入。例如:
(1+30)/3=
输出样例:
在这里给出相应的输出。例如:
10
题目分析
使用数字栈和符号栈进行计算,可给符号赋予优先级(也可像我一向直接全部手写,笨比哭泣)。
代码实现如下
#include<stdio.h>
int main(){
char p[256],t,get,tok;
int q[128],topp=-1,topq=-1,k=0,i=0,x,y,z,stp,stq;
t=getchar();
while(t!='='){
if(t>='0'&&t<='9'){
k=k*10;
k+=t-'0';
}
else {
if(k!=0){
q[++topq]=k;
k=0;
}
switch(t){
case '+':
while(p[topp]=='+'||p[topp]=='-'||p[topp]=='*'||p[topp]=='/'){
get=p[topp--];
switch(get){
case '+':y=q[topq--];x=q[topq--];z=x+y;q[++topq]=z;break;
case '-':y=q[topq--];x=q[topq--];z=x-y;q[++topq]=z;break;
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
p[++topp]=t;break;
case '-':
while(p[topp]=='+'||p[topp]=='-'||p[topp]=='*'||p[topp]=='/'){
get=p[topp--];
switch(get){
case '+':y=q[topq--];x=q[topq--];z=x+y;q[++topq]=z;break;
case '-':y=q[topq--];x=q[topq--];z=x-y;q[++topq]=z;break;
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
p[++topp]=t;break;
case '*':
while(p[topp]=='*'||p[topp]=='/'){
get=p[topp--];
switch(get){
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
p[++topp]=t;break;
case '/':
while(p[topp]=='*'||p[topp]=='/'){
get=p[topp--];
switch(get){
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
p[++topp]=t;break;
case '(':i++;p[++topp]=t;break;
case ')':
while(p[topp]!='('){
get=p[topp--];
switch(get){
case '+':y=q[topq--];x=q[topq--];z=x+y;q[++topq]=z;break;
case '-':y=q[topq--];x=q[topq--];z=x-y;q[++topq]=z;break;
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
topp--;i--;break;
}
}
t=getchar();
}
if(k!=0)q[++topq]=k;
while(topp!=-1){
get=p[topp--];
switch(get){
case '+':y=q[topq--];x=q[topq--];z=x+y;q[++topq]=z;break;
case '-':y=q[topq--];x=q[topq--];z=x-y;q[++topq]=z;break;
case '*':y=q[topq--];x=q[topq--];z=x*y;q[++topq]=z;break;
case '/':y=q[topq--];if(y==0){printf("NaN");return 0;}x=q[topq--];z=x/y;q[++topq]=z;break;
}
}
printf("%d",q[0]);
return 0;
}
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
题目分析
即维护一个单调队列,每次取前i项和减去改区间最小前t项和作为结果,并及时更新结果区间。
代码实现如下
#include <stdio.h>
int a[500010],queue[500010],s,e,max=0,top=0,f;
int main(){
int n,m,i,k,t;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&k);
a[i]+=a[i-1]+k;
t=a[i]-a[queue[f]];
if(t>max){
s=queue[f];
e=i;
max=t;
}
if(i-queue[f]==m)f++;
while(a[queue[top]]>a[i]&&top>=f)top--;
queue[++top]=i;
}
printf("%d %d %d",max,s+1,e);
return 0;
}