2024.3.28|2024年华北水利水电大学第六届ACM-ICPC程序设计大赛-线上初赛

2024.3.14|华北水利水电大学江淮校区ACM社团训练赛

7-1.斐波那契数列
7-2.字符串处理
7-3.董大佬和耗子吃西瓜
7-4.三角形问题
7-5.众数
7-6.集训队选拔
7-7.寻找一个子序列
7-8.哥布林的舞会
7-9.病毒溯源
7-10.跳格子
7-11.任务分配

心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。
在这里插入图片描述

斐波那契数列

题目
有这样一个特殊的递增序列,在这个序列中数字的排列如下:0,1,1,2,3,5,8,13,21,34,55……。这个序列的特点是:从第三项起,每一项都是紧挨着的前两项的和。现在请你帮助他来数数,告诉他这个数列任一项(项数小于33)的数字是多少?

输入格式:
输入要求的项数。
输出格式:
输出数据项的值。
示例1
输入样例
在这里给出一组输入。例如:
10
输出样例
在这里给出相应的输出。例如:
34

实践代码:

int f(int x){//斐波那契数列
    if(x==1) return 0;
    if(x==2) return 1;
    return f(x-1)+f(x-2);
}
void solve(){
    int n;cin>>n;
    cout<<f(n);
}

字符串处理

题目
用户输入一个字符串,其中有一些字母和数字,现在需要把字符串中的字母挑出来,并且无论大小写,都改成大写输出出来。请写出一个完整的程序来完成这件事。

输入格式:
输入一个字符串s,长度小于100。
输出格式:
输出处理后的字符串。
示例1
输入样例
在这里给出一组输入。例如:
nc123WU
输出样例
在这里给出相应的输出。例如:
NCWU

实践代码:

void solve(){
    string s;cin>>s;
    for(int i=0;i<s.length();i++){
        if(s[i]>='a'&&s[i]<='z') {char c=s[i]-32;cout<<c;}
        if(s[i]>='A'&&s[i]<='Z') cout<<s[i];
    }
}

董大佬和耗子吃西瓜

题目
在一个炎热的夏天,耗子哥和董大佬在活动室打了一天的比赛,比赛结束时,他们觉得非常的渴,于是决定买来一个西瓜两个人分开吃,但是耗子哥是强迫症,他想要将西瓜分成两份并且两份都必须是偶数,不然就坚决不吃,董大佬在旁边看耗子哥挑西瓜看的很着急,因为他已经饥渴难耐了,他希望你能帮帮他们,看一看耗子哥此时挑选的西瓜是否满足条件。

输入格式:
给出一个正整数w代表西瓜的重量(1<=w<=100)
输出格式:
如果西瓜的重量满足耗子哥的要求,输出YES,
否则输出NO
示例1
输入样例
在这里给出一组输入。例如:
4
输出样例
在这里给出相应的输出。例如:
YES

实践代码:

void solve(){
    int w;cin>>w;
    if(w%2==0){
        if((w/2)%2==0) cout<<"YES";
        else cout<<"NO";
    }
    else cout<<"NO";
}

三角形问题

题目
李华正在训练一个三角形分类模型,他手里有一堆数据,你能帮他标注一下么?
给定三个正整数,代表可能组成一个三角形的三条边长。
将其组成三角形后
如果是直角三角形,输出"right";如果是等边三角形,输出"equilateral"; 如果不能组成 一个三角形,输出"error", 否则,输出"normal".
输入格式:
输入为三个正整数a b c
(1<=a,b,c<=10000)
输出格式:
一串字符串如题所说
示例1
输入样例
在这里给出一组输入。例如:
3 4 5
输出样例
在这里给出相应的输出。例如:
right

实践代码:

void solve(){
   int a,b,c;cin>>a>>b>>c;
   if((a+b<=c)||(a+c<=b)||(b+c<=a)) cout<<"error";
   else{
       if(a==b&&a==c) cout<<"equilateral";
       else if((a*a+b*b==c*c)||(a*a+c*c==b*b)||(b*b+c*c==a*a)) cout<<"right";
       else cout<<"right";
   }
}

众数

题目
由文件给出N个1到 30000 间无序数正整数,其中 1≤N≤10000,同一个正整数可能会出现多次,出现次数最多的整数称为众数。求出它的众数及它出现的次数。
输入格式:
输入文件第一行是正整数的个数 N,第二行开始为 N 个正整数。
输出格式:
输出文件有若干行,每行两个数,第 1 个是众数,第 2 个是众数出现的次数。
示例1
输入样例
在这里给出一组输入。例如:
12
2 4 2 3 2 5 3 7 2 3 4 3
输出样例
在这里给出相应的输出。例如:
2 4
3 4

实践代码:

void solve(){
   int n;cin>>n;
   vector<int> a(n),b(30001);
   for(int i=0;i<n;i++) {cin>>a[i];b[a[i]]++;}
   int mx=0;
   for(int i=1;i<=30000;i++){
       if(b[i]!=0) mx=max(mx,b[i]);
   }
   for(int i=1;i<=30000;i++){
       if(b[i]==mx) cout<<i<<' '<<mx<<endl;
   }
}

集训队选拔

题目
杨老师批改完数据结构期末考试试卷后,需要把全班学生的成绩做个排序,成绩高的在前,成绩低的在后。为了备战即将开始的天梯赛,需要从中选取成绩最好的前n位同学。现在请你帮助他完成选拔队员的任务。

输入格式:
第一行输入两个整数m,n。0<n<=m<=1000。
第二行包含m个整数,每一个整数表示一位同学的成绩x。0<=x<=1012
输出格式:
输出包含一行n个整数,所有数按从大到小排序。
示例1
输入样例
在这里给出一组输入。例如:
10 5
1 2 3 4 5 6 7 8 9 10
输出样例
在这里给出相应的输出。例如:
10 9 8 7 6

实践代码:

void solve(){
   int m,n;cin>>m>>n;
   vector<int> a(m);
   for(int i=0;i<m;i++) cin>>a[i];
   sort(a.begin(),a.end(),greater<int>());
   for(int i=0;i<n;i++) cout<<a[i]<<' ';
}

寻找一个子序列

题目
在数列A中找到一个具有下面特点的子序列。

  1. 给定由不相同的n个整型元素组成的序列A:{A(1),A(2),…,A(i),…,A(n)};
  2. 寻找一个序列I:{i1,i2,i3,……,ie},且i1<i2<i3<…<ie,使得A(i1)<=A(i2)<=…<=A(ie);
  3. 在所有这些序列中,元素数量最多的那个序列就是我们要寻找的子序列。

输入格式:
一行用空格隔开的多个整数,整数数量最多100个。
输出格式:
输出子序列的最大个数;
示例1
输入样例
在这里给出一组输入。例如:
13 7 9 16 38 24 37 18 44 19 21 22 63 15
输出样例
在这里给出相应的输出。例如:
8

实践代码:

vector<int> dp(N,1);
void solve(){
    int n=0;
    vector<int> a(101);
    while(cin>>a[n]) n++;
    for(int i=1;i<n;i++){
        for(int j=0;j<i;j++)
           if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1);
    }
    int mx=0;
    for(int i=0;i<n;i++){
        mx=max(mx,dp[i]);
    }
    cout<<mx;

}

哥布林的舞会

题目
一群洞穴哥布林为了庆祝新冠疫情解封,举行了一个盛大的舞会。每个参加舞会的哥布林都拿到了一个序号牌,记录了他进入舞厅的次序(从1开始的升序)。
哥布林们彼此选择舞伴遵循一个古老的传统,先进入舞厅的哥布林要选择身高比他低的哥布林作为舞伴。
举个栗子,第i个顺序进入舞厅的哥布林身高为hi,第j个进入的哥布林身高为hj。若存在i<j,且hi>hj,则两个人可以做彼此的舞伴。

例如样例中可能组成的舞伴有3个组合:
1号哥布林和2号哥布林,身高分别为3和2;
1号哥布林和4号哥布林,身高分别为3和2;
3号哥布林和4号哥布林,身高分别为3和2。

输入格式:
第一行为参加舞会的哥布林总数n,接下来的n行记录了次序进入舞厅的哥布林身高。
输出格式:
所有可能的舞伴组合数。
示例1
输入样例
在这里给出一组输入。例如:
4
3
2
3
2
输出样例
在这里给出相应的输出。例如:
3

实践代码:

vector<int> a(N),b(N);//a是待排序数组,b是辅助排序数组
int ans=0;
void msort(int l,int r){
    if(l==r) return;
    int mid=(l+r)/2;
    msort(l,mid);
    msort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){
        if(a[i]<=a[j]) {b[k]=a[i];k++;i++;}
        else {b[k]=a[j];k++;j++;ans+=mid-i+1;}
    }
    while(i<=mid) {b[k]=a[i];k++;i++;}
    while(j<=r) {b[k]=a[j];k++;j++;}
    for(int i=l;i<=r;i++) a[i]=b[i];
}

void solve(){
    int n;cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    msort(0,n-1);
    cout<<ans;
}

病毒溯源

在这里插入图片描述

题目
病毒容易发生变异。某种病毒可以通过突变产生若干变异的毒株,而这些变异的病毒又可能被诱发突变产生第二代变异,如此继续不断变化。
现给定一些病毒之间的变异关系,要求你找出其中最长的一条变异链。
在此假设给出的变异都是由突变引起的,不考虑复杂的基因重组变异问题 —— 即每一种病毒都是由唯一的一种病毒突变而来,并且不存在循环变异的情况。

输入格式:
输入在第一行中给出一个正整数 N(≤104),即病毒种类的总数。于是我们将所有病毒从 0 到 N−1 进行编号。

随后 N 行,每行按以下格式描述一种病毒的变异情况:

k 变异株1 …… 变异株k

其中 k 是该病毒产生的变异毒株的种类数,后面跟着每种变异株的编号。第 i 行对应编号为 i 的病毒(0≤i<N)。题目保证病毒源头有且仅有一个。
输出格式:
首先输出从源头开始最长变异链的长度。

在第二行中输出从源头开始最长的一条变异链,编号间以 1 个空格分隔,行首尾不得有多余空格。如果最长链不唯一,则输出最小序列。

注:我们称序列 { a1,⋯,an} 比序列 { b1,⋯,bn} “小”,如果存在 1≤k≤n 满足 ai=bi对所有 i<k 成立,且 a k<bk
示例1
输入样例
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1
输出样例
4
0 4 9 1

实践代码:

const int N = 1e5+10;
int n,k;
set<int> s[N];
int st[N],d[N],f[N],ans[N];//st用来标记是否为孩子,d用来记录此时最长深度,f用来更新父结点,ans用来存储最大深度对应的每个点
int root,mx,mxi;
void dfs(int u){
    for(auto t:s[u]){//t是u的孩子
        d[t]=d[u]+1;//孩子的深度=父节点深度+1
        if(d[t]>mx) mx=d[t],mxi=t;//更新最长深度mx并且最大深度对应的最下面的节点mxi更新为孩子
        dfs(t);
    }
}
void solve(){
    cin>>n;//结点总数
    for(int i=0;i<n;i++){
        cin>>k;//每个点的孩子数
        for(int j=1;j<=k;j++){
            int u;cin>>u;//每个点的孩子
            s[i].insert(u);//用set存储树(优点:结点按字典序排列,符合题意,便于搜索)
            f[u]=i;st[u]=1;//f[u]=i:u结点的父节点是i,st[u]=1:标记此时结点u已经成为别人的孩子(绝对不可能是根节点)
        }
    }
    for(int i=0;i<n;i++) if(!st[i]) root=i;//没有被标记过的点就是唯一的根结点,用root记录
    mx=1,mxi=root,d[root]=1;//初始化,mx代表最长路径的深度(长度),mxi代表最长路径中的最后一个点,d代表此时深度
    dfs(root);//从根结点开始遍历
    int pos=mxi;
    cout<<mx<<endl;//输出最大深度
    /*由于父节点都是唯一的,所以找到的最大深度的每一个点都是唯一的,且set中的结点按从小到大顺序存储,先找到的最大深度的每一个点一定是字典序最小的*/
    for(int i=mx;i>=1;i--){ans[i]=pos;pos=f[pos];}//从最后一个结点开始找它的父亲,并用ans存储此路径的每一个点
    for(int i=1;i<=mx;i++){cout<<ans[i];if(i!=mx) cout<<' ';}//输出每一个点
}

跳格子

题目
小时候,没有什么娱乐的,放学后就同学一起玩跳格子。那时候的跳格子,只有9个格,写上数字,从这头1跳到那头9,再跳回来。这个游戏有了升级版。画的格子变了样,规则也变了。如图所示。
在这里插入图片描述

新跳格子规则:

1)可以从任意标号开始,往较大标号的相邻格子跳;

2)只能从小的往大的跳;

3)边界挨着的格子就算相邻。

现在问:从编号为K的格子开始爬到N,K<N。问有多少种跳法?

输入格式:
一行有两个输入数据: K,N
输出格式:
输出一个数字(有多少种跳法)
示例1
输入样例
3 16
输出样例
377

实践代码:

vector<int> add(vector<int> a,vector<int> b){
    int t=0;
    vector<int> c;
    for(int i=0;i<a.size()||i<b.size();i++){
        if(i<a.size()) t+=a[i];
        if(i<b.size()) t+=b[i];
        c.push_back(t%10);
        t/=10;
    }
    if(t) c.push_back(1);
    return c;
}
void solve(){
    int k,n;cin>>k>>n;
    vector<int> a;
    vector<int> b;
    vector<int> c;
    a.push_back(0);//1
    b.push_back(1);//2
    for(int i=1;i<=n-k;i++){
        c=add(a,b);
        a=b;
        b=c;
    }
    for(int i=c.size()-1;i>=0;i--) cout<<c[i];
}

任务分配

题目
装修公司接到一个装修任务,任务中共有n件工作,n件工作可以分配给n个小组。将工作i分配给第j个小组所需的费用为cij。试设计一个算法,为每一个小组都分配一件不同的工作,并使总费用达到最小。设计一个算法,对于给定的工作费用,计算最佳工作分配方案,使总费用达到最小。

输入格式:
第一行有1个正整数n (1≤n≤20)。接下来的n行,每行n个数,第i行表示第i个小组分别完成这n件工作所需要的费用。
输出格式:
输出计算出的最小总费用。
示例1
输入样例
在这里给出一组输入。例如:
3
4 2 5
2 3 6
3 4 5
输出样例
在这里给出相应的输出。例如:
9

实践代码:

int a[21][21],vis[21];
int n,mn=INF,tmp=0;
void dfs(int u,int t){//u代表当前小组,t代表当前的总费用
    if(u==n+1) {mn=min(mn,t);return;}//沿枝干搜索到尽头
    for(int i=1;i<=n;i++){
        if(t>=mn) return;//剪枝,如果当前费用大于目前最少费用就没必要再搜下去了
        if(!vis[i]){
            tmp=t+a[u][i];//当前费用总和
            vis[i]=1;
            dfs(u+1,tmp);//递归下一组
            vis[i]=0;//回溯
        }
    }
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++) cin>>a[i][j];
    }
    dfs(1,0);
    cout<<mn;
}

心有猛虎,细嗅蔷薇。再见了朋友~

  • 24
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值