HNUCM Contest1092 - 2020年春季ACM集訓隊熱身賽-第3場 比賽題解

Contest1092 - 2020年春季ACM集訓隊熱身賽-第3場

比賽原地址: 傳送門


推薦閱讀: 【白嫖黨】如何把前端學好?看完這篇,直呼:太強了!(歷經半個月之作)

問題 A: 數字分類

題目描述

給定一系列正整數,請按要求對數字進行分類,並輸出以下5個數字:
A1 = 能被5整除的數字中所有偶數的和;
A2 = 將被5除後餘1的數字按給出順序進行交錯求和,即計算n1-n2+n3-n4…;
A3 = 被5除後餘2的數字的個數;
A4 = 被5除後餘3的數字的平均數,精確到小數點後1位;
A5 = 被5除後餘4的數字中最大數字。

輸入

每個輸入包含1個測試用例。每個測試用例先給出一個不超過1000的正整數N,隨後給出N個不超過10000的待分類的正整數。數字間以空格分隔。

輸出

對給定的N個正整數,按題目要求計算A1~A5並在一行中順序輸出。數字間以空格分隔,但行末不得有多餘空格。
若其中某一類數字不存在,則在相應位置輸出“N”。

樣例輸入

13 1 2 3 4 5 6 7 8 9 10 20 16 18

樣例輸出

30 11 2 9.7 9

解題思路

沒用到什麼特殊的方法,注意一些細節就好了,具體看如下代碼好了

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e3+5;
int n,x;
int a[10];
int main(){
    cin>>n;
    int k=1,cc=0,ans=0;
    for(int i=0;i<n;i++){
        cin>>x;
        if(x%5==0&&x%2==0) a[1]+=x;
        else if(x%5==1)  a[2]+=k*x,k=-k;
        else if(x%5==2) a[3]++;
        else if(x%5==3) a[4]+=x,++cc;
        else if(x%5==4) a[5]=max(a[5],x);
    }
    for(int i=1;i<=3;i++){
        if(!a[i]) cout<<"N ";
        else cout<<a[i]<<" ";
    }
    if(!a[4]) cout<<"N ";
        else printf("%.1f ",a[4]*1.0/cc);
    if(!a[5]) cout<<"N";
        else cout<<a[5]<<endl;
    return 0;
}

問題 B: 福爾摩斯的約會

題目描述

大偵探福爾摩斯接到一張奇怪的字條:“我們約會吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”。大偵探很快就明白了,字條上奇怪的亂碼實際上就是約會的時間“星期四 14:04”,因爲前面兩字符串中第1對位置相同的大寫英文字母是第4個字母’D’,代表星期四(大寫字符A到G表示星期一到星期日);第2對位置相同的大寫字母(A-N)或數字(0-9)表示HH,這裏相同的字母是’E’,是第5個英文字母,代表一天裏的第14個鐘頭(於是一天的0點到23點由數字0到9、以及大寫字母A到N表示);後面兩字符串第1對相同的英文字母’s’(區分大小寫)同時出現在第4個位置(從0開始計數)上,代表第4分鐘。現給定兩對字符串,請幫助福爾摩斯解碼得到約會的時間。
輸入
輸入在4行中分別給出4個非空、不包含空格、且長度不超過60的字符串。
輸出
在一行中輸出約會的時間,格式爲“DAY HH:MM”,其中“DAY”是某星期的3字符縮寫,即MON表示星期一,TUE表示星期二,WED表示星期三,THU表示星期
四,FRI表示星期五,SAT表示星期六,SUN表示星期日。題目輸入保證每個測試存在唯一解。

樣例輸入

3485djDkxh4hhGE
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm

樣例輸出

THU 14:04

解題思路

總共有4個字符串,前兩個用來判斷是星期幾和小時,後兩個是用來判斷分鐘

每次都只取第一個相等,即如果達到了符合條件的相等,就不用判斷後面是否相等了

然後需要注意題目條件,我一開始條件搞錯了,就…

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
const int maxn=1e2+5;
char s1[maxn],s2[maxn];
char day[7][maxn]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
int main(){
    cin>>s1>>s2;
    int dd=0,idx=0,hh=0,mm=0;
    for(int i=0;s1[i]&&s2[i];i++){
        if(s1[i]==s2[i]&&s1[i]>='A'&&s1[i]<='G'){
            dd=s1[i]-'A';
            idx=i;
            break;
        }
    }
    for(int i=idx+1;s1[i]&&s2[i];i++){
        if(s1[i]==s2[i]&&s1[i]>='0'&&s1[i]<='9'){
            hh=s1[i]-'0';
            break;
        }
        else if(s1[i]==s2[i]&&s1[i]>='A'&&s1[i]<='N'){
            hh=s1[i]-'A'+10;
            break;
        }
    }
    cin>>s1>>s2;
    for(int i=0;s1[i]&&s2[i];i++){
        if(s1[i]==s2[i]&&((s1[i]>='a'&&s1[i]<='z')||(s1[i]>='A'&&s1[i]<='Z'))){
           mm=i;
           break;
        }
    }
    cout<<day[dd]<<" ";
    printf("%02d:",hh);
    printf("%02d\n",mm);
    return 0;
}

問題 C: 德才論

題目描述

宋代史學家司馬光在《資治通鑑》中有一段著名的“德才論”:“是故才德全盡謂之聖人,才德兼亡謂之愚人,德勝才謂之君子,才勝德謂之
小人。凡取人之術,苟不得聖人,君子而與之,與其得小人,不若得愚人。”

現給出一批考生的德才分數,請根據司馬光的理論給出錄取排名。

輸入

輸入第1行給出3個正整數,分別爲:N(<=10^5),即考生總數;L(>=60),爲錄取最低分數線,即德分和才分均不低於L的考生纔有資格
被考慮錄取;H(<100),爲優先錄取線——德分和才分均不低於此線的被定義爲“才德全盡”,此類考生按德才總分從高到低排序;才分不到
但德分到線的一類考生屬於“德勝才”,也按總分排序,但排在第一類考生之後;德才分均低於H,但是德分不低於才分的考生屬於“才德兼
亡”但尚有“德勝才”者,按總分排序,但排在第二類考生之後;其他達到最低線L的考生也按總分排序,但排在第三類考生之後。

隨後N行,每行給出一位考生的信息,包括:准考證號、德分、才分,其中准考證號爲8位整數,德才分爲區間[0, 100]內的整數。數字間以空格分隔。

輸出

輸出第1行首先給出達到最低分數線的考生人數M,隨後M行,每行按照輸入格式輸出一位考生的信息,考生按輸入中說明的規則從高到低排序。當某類考生中有多人總分相同時,按其德分降序排列;若德分也並列,則按准考證號的升序輸出。

樣例輸入

14 60 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60

樣例輸出

12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 64 90

解題思路

這道題,比賽時沒時間做了…

交了幾發,wa了,但樣例沒問題,於是就找問題,結果出乎意料吧
改了兩個地方就過了…

原來版本:

stu[cnt].str=s,stu[cnt].dd=d,stu[cnt].cc=c,stu[cnt].sum=d+c;

現在版本:

strcpy(stu[cnt].str,s),stu[cnt].dd=d,stu[cnt].cc=c,stu[cnt].sum=d+c;

原來版本:

bool cmp(node x,node y){
    if(x.w!=y.w) return x.w>y.w;
    if(x.sum!=y.sum) return x.sum>y.sum;
    if(x.dd!=y.dd) return x.dd>y.dd;
    return x.str<y.str<0;
}

現在版本:

bool cmp(node x,node y){
    if(x.w!=y.w) return x.w>y.w;
    if(x.sum!=y.sum) return x.sum>y.sum;
    if(x.dd!=y.dd) return x.dd>y.dd;
    return strcmp(x.str,y.str)<0;
}

看完之後,我:???下次記得調用函數吧。。。


好了,說一下解題思路:

下面這段代碼,肯定不是一下子就寫出這麼整齊的,結構體裏面原本就三個變量的,後續根據所需才慢慢加的。

此題很關鍵的就在於如何把結構體按照已知條件進行排序,而且題目還分了批次。

這裏不妨將幾類人根據權值排序,即下面代碼中的w

  • 第一類考生——聖人(德才兼備) 定義權值 100
  • 第二類考生——德達到優先錄取,而纔沒達到,君子(德勝才) 定義權值 90
  • 第三類考生——德才分均低於H,但是德分不低於才分 定義權值 80
  • 第四類考生——達到最低線L 定義權值 70

如何排序?

  • 首先,根據權值排序
  • 然後,根據總分排序
  • 總分相同,根據德分降序排序
  • 德分相同,按准考證號的升序

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
const int maxn=1e5+5;
struct node{
    char str[20];
    int dd,cc;
    int w;
    int sum;
}stu[maxn];
int n,ls,hs,d,c;
char s[20];
bool cmp(node x,node y){
    if(x.w!=y.w) return x.w>y.w;
    if(x.sum!=y.sum) return x.sum>y.sum;
    if(x.dd!=y.dd) return x.dd>y.dd;
    return strcmp(x.str,y.str)<0;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>ls>>hs;
    int cnt=0;
    for(int i=0;i<n;i++){
        cin>>s>>d>>c;
        if(d>=ls&&c>=ls){
            strcpy(stu[cnt].str,s),stu[cnt].dd=d,stu[cnt].cc=c,stu[cnt].sum=d+c;
            if(d>=hs&&c>=hs) stu[cnt].w=100;
            else if(d>=hs&&c<hs) stu[cnt].w=90;
            else if(d<hs&&c<hs&&d>=c) stu[cnt].w=80;
            else stu[cnt].w=70;
            ++cnt;
        }
    }
    sort(stu,stu+cnt,cmp);
    cout<<cnt<<endl;
    for(int i=0;i<cnt;i++)
        cout<<stu[i].str<<" "<<stu[i].dd<<" "<<stu[i].cc<<endl;
    return 0;
}

問題 D: 錘子剪刀布

題目描述

大家應該都會玩“錘子剪刀布”的遊戲:
現給出兩人的交鋒記錄,請統計雙方的勝、平、負次數,並且給出雙方分別出什麼手勢的勝算最大。

輸入

輸入第1行給出正整數N(<=10^5),即雙方交鋒的次數。隨後N行,每行給出一次交鋒的信息,即甲、乙雙方同時給出的的手勢。C代表“錘子”、J代表“剪刀”、B代表“布”,第1個字母代表甲方,第2個代表乙方,中間有1個空格。

輸出

輸出第1、2行分別給出甲、乙的勝、平、負次數,數字間以1個空格分隔。第3行給出兩個字母,分別代表甲、乙獲勝次數最多的手勢,中間有1個空格。如果解不唯一,則輸出按字母序最小的解。

樣例輸入

10
C J
J B
C B
B B
B C
C C
C B
J B
B C
J J

樣例輸出

5 3 2
2 3 5
B B

解題思路

如下述代碼所示,這道題寫的有點糊了,一開始各種 if 暴力判斷,寫着寫着輸出不太對勁,b一直沒有贏過?

卡了一段時間後,想着整合起來,然後輸出處理了一下。

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
const int maxn=1e3+5;
int n,x;
int main(){
    int s=0,f=0,p=0;
    int ac=0,aj=0,ab=0,bc=0,bj=0,bb=0;
    char a[2],b[2];
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        cin>>a>>b;
        if((a[0]=='C'&&b[0]=='J')||(a[0]=='J'&&b[0]=='B')||(a[0]=='B'&&b[0]=='C')){
            s++;
            if(a[0]=='C')ac++;
            if(a[0]=='B')ab++;
            if(a[0]=='J')aj++;
        }
        else if((a[0]=='C'&&b[0]=='C')||(a[0]=='J'&&b[0]=='J')||(a[0]=='B'&&b[0]=='B')){
            p++;
        }else {
            f++;
            if(b[0]=='C')bc++;
            if(b[0]=='B')bb++;
            if(b[0]=='J')bj++;
        }
    }
    cout<<s<<" "<<p<<" "<<f<<endl;
    cout<<f<<" "<<p<<" "<<s<<endl;
    /*if(aj>ac&&aj>ab) cout<<"J ";
    else if(ab>ac&&ab>aj) cout<<"B ";
    else cout<<"C ";
 
    if(bj>bc&&bj>bb) cout<<"J ";
    else if(bb>bc&&bb>bj) cout<<"B ";
    else cout<<"C ";*/
    cout<<((ac>ab&&ac>=aj)?'C':(ab>=aj?'B':'J'))<<" ";
    cout<<((bc>bb&&bc>=bj)?'C':(bb>=bj?'B':'J'))<<endl;
    return 0;
}

問題 E: 月餅

題目描述

月餅是中國人在中秋佳節時吃的一種傳統食品,不同地區有許多不同風味的月餅。現給定所有種類月餅的庫存量、總售價、以及市場的最大需求量,請你計算可以獲得的最大收益是多少。

注意:銷售時允許取出一部分庫存。樣例給出的情形是這樣的:假如我們有3種月餅,其庫存量分別爲18、15、10萬噸,總售價分別爲75、72、45億元。如果市場的最大需求量只有20萬噸,那麼我們最大收益策略應該是賣出全部15萬噸第2種月餅、以及5萬噸第3種月餅,獲得 72 + 45/2 = 94.5(億元)。

輸入

每個輸入包含1個測試用例。每個測試用例先給出一個不超過1000的正整數N表示月餅的種類數、以及不超過500(以萬噸爲單位)的正整數D表示市場最大需求量。隨後一行給出N個正實數表示每種月餅的庫存量(以萬噸爲單位);最後一行給出N個正實數表示每種月餅的總售價(以億元爲單位)。數字間以空格分隔。

輸出

對每組測試用例,在一行中輸出最大收益,以億元爲單位並精確到小數點後2位。

樣例輸入

3 20
18 15 10
75 72 45

樣例輸出

94.50

解題思路

這道題再熟悉不過了,當年PAT正式比賽前的一場全國模擬賽就是出的這一道,沒啥說的,裸裸の貪心

AC代碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
struct node{
    double w,v,bt;
}stu[maxn];
int n;
double sum;
bool cmp(node x,node y){
    return x.bt>y.bt;
}
int main(){
    while(~scanf("%d %lf",&n,&sum)){
        for(int i=0;i<n;i++) scanf("%lf",&stu[i].w);
        for(int i=0;i<n;i++){
            scanf("%lf",&stu[i].v);
            stu[i].bt=(double)stu[i].v/stu[i].w;
        }
        sort(stu,stu+n,cmp);
        double ans=0;
        for(int i=0;i<n;i++){
            if(stu[i].w>=sum){
                ans+=(double)stu[i].bt*sum;
                break;
            }else{
                ans+=stu[i].v;
                sum-=stu[i].w;
            }
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

問題 F: 打印沙漏

題目描述

本題要求你寫個程序把給定的符號打印成沙漏的形狀。例如給定17個“*”,要求按下列格式打印

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

所謂“沙漏形狀”,是指每行輸出奇數個符號;各行符號中心對齊;相鄰兩行符號數差2;符號數先從大到小順序遞減到1,再從小到大順序遞
增;首尾符號數相等。

給定任意N個符號,不一定能正好組成一個沙漏。要求打印出的沙漏能用掉儘可能多的符號。

輸入

輸入在一行給出1個正整數N(N<=1e5)和一個符號,中間以空格分隔。

輸出

首先打印出由給定符號組成的最大的沙漏形狀,最後在一行中輸出剩下沒用掉的符號數。

樣例輸入

19 *

樣例輸出

*****
 ***
  *
 ***
*****
2

解題思路

打印沙漏問題,PAT原題。

注意一個公式:

需要字符總數=2*h*h-1(其中h表示沙漏“一半”的形狀)

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e3+5;
int n,h;
char s[5];
int main(){
    cin>>n>>s;
    h=sqrt((n+1)/2);
    for(int i=h;i>=1;i--){
        for(int j=1;j<=h-i;j++) cout<<" ";
        for(int j=1;j<=2*i-1;j++) cout<<s[0];
        cout<<endl;
    }
    for(int i=2;i<=h;i++){
        for(int j=1;j<=h-i;j++) cout<<" ";
        for(int j=1;j<=2*i-1;j++) cout<<s[0];
        cout<<endl;
     }
     ll ans=n-(2*h*h-1);
     cout<<ans<<endl;
    return 0;
}

問題 G: 組個最小數

題目描述

給定數字0-9各若干個。你可以以任意順序排列這些數字,但必須全部使用。目標是使得最後得到的數儘可能小(注意0不能做首位)。例如:
給定兩個0,兩個1,三個5,一個8,我們得到的最小的數就是10015558。
現給定數字,請編寫程序輸出能夠組成的最小的數。

輸入

每個輸入包含1個測試用例。每個測試用例在一行中給出10個非負整數,順序表示我們擁有數字0、數字1、……數字9的個數。整數間用一個空格分隔。
10個數字的總個數不超過200,且至少擁有1個非0的數字。

輸出

在一行中輸出能夠組成的最小的數。

樣例輸入

2 2 0 0 0 3 0 0 1 0

樣例輸出

10015558

解題思路

按照題意來說,只要0不打頭,其它按順序輸出即可

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,v,sizeof(a))
using namespace std;
const int maxn=1e3+5;
map<int,int> mp;
int main(){
    mp.clear();
    int x;
    for(int i=0;i<=9;i++){
        cin>>x;
        mp[i]=x;
    }
    if(mp[0]){
        for(int i=1;i<=9;i++){
            if(mp[i]){
                cout<<i;
                mp[i]--;
            break;
            }
        }
    }
    for(int i=0;i<=9;i++){
        while(mp[i]){
            cout<<i;
            mp[i]--;
        }
    }
    cout<<endl;
    return 0;
}

問題 H: 跟奧巴馬一起編程

題目描述

美國總統奧巴馬不僅呼籲所有人都學習編程,甚至以身作則編寫代碼,成爲美國歷史上首位編寫計算機代碼的總統。
2014年底,爲慶祝“計算機科學教育周”正式啓動,奧巴馬編寫了很簡單的計算機代碼:在屏幕上畫一個正方形。現在你也跟他一起畫吧!

輸入

多組輸入,每組數據一行,每行給出正方形邊長N(3<=N<=20)和組成正方形邊的某種字符C,間隔一個空格。

輸出

輸出由給定字符C畫出的正方形。但是注意到行間距比列間距大,所以爲了讓結果看上去更像正方形,我們輸出的行數實際上是列數的50%(四捨五入取整)。
每組數據後空一行

樣例輸入

10 a

樣例輸出

aaaaaaaaaa
a        a
a        a
a        a
aaaaaaaaaa

解題思路

模擬即可

AC代碼

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn=1e3+5;
int n;
char s[10];
int main(){
    while(cin>>n>>s){
    int m=(n+1)/2;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(i==0||i==m-1||j==0||j==n-1) cout<<s[0];
            else cout<<" ";
        }
        cout<<endl;
    }
    cout<<endl;
    }
    return 0;
}

結尾

Github上面可以直接查看所有前端知識點梳理,github傳送門,覺得不錯,點個Star★,好運連連,Offer終究鼠於你,持續更新中。另外,也可以關注微信公衆號:小獅子前端Vue,源碼以及資料今後都會放在裏面。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章