本次比賽共240名同學提交代碼,其中238名同學通過1題以上,最高通過題數(shù)為7題,共一人。
寫在前面
本次比賽面向19級新生,考察的知識點有:分支、循環(huán)、數(shù)組、排序、最大公約數(shù)。
題目考察的知識點較為簡單,不涉及較難算法,更多得是考察19級新生的思維和邏輯能力。
題解
A題-盤古開天地
Problem Description
很久很久以前,天和地還沒有分開,宇宙混沌一片。有個叫盤古的巨人,在這混沌之中,一直睡了一萬八千年。
有一天,盤古突然醒了。他見周圍一片漆黑,就掄起大斧頭,朝眼前的黑暗猛劈過去。只聽一聲巨響,混沌一片的東西漸漸分開了。輕而清的東西,緩緩上升,變成了天;重而濁的東西,慢慢下降,變成了地。
天和地分開以后,盤古怕它們還會合在一起,就頭頂著天,用腳使勁蹬著地。天每天升高一丈,盤古也隨著越長越高。這樣不知過多少年,天和地逐漸成形了,盤古也累得倒了下去。
盤古倒下后,他的身體發(fā)生了巨大的變化。他呼出的氣息,變成了四季的風和飄動的云;他發(fā)出的聲音,化作了隆隆的雷聲。他的雙眼變成了太陽和月亮;他的四肢,變成了大地上的東、西、南、北四極;他的肌膚,變成了遼闊的大地,他的血液,變成了奔流不息的江河,他的汗,變成了滋潤萬物的雨露......
Input
輸入包含一個正整數(shù)N(1≤N≤100000000)
Output
輸出一行。
當輸入為1時,請輸出盤古沉睡的年數(shù),即18000
當輸入為其他時,請輸出0
Sample Input 1
1
Sample Output 1
18000
Sample Input 2
2
Sample Output 2
0
Hint
無
思路:
簽到題
參考代碼:
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
if(n==1)
printf("18000");
else
printf("0");
return 0;
}
易錯點分析
1、只要學會了分支和熟悉SCNUOJ的輸入輸出之后,相信A、B題沒有什么難度,是兩道合格的簽到題。
B題-猜拳
Problem Description
猜拳!你要贏,明白嗎!用1代表剪刀,2代表石頭,3代表布!電腦出什么,你就要輸出對應贏的手勢!什么,你不明白?石頭贏剪刀,布贏石頭,剪刀贏布!你一定要贏過電腦呀!
Input
輸入1,2或3,代表對應的手勢。
Output
輸出1,2或3,表示能贏過輸入的手勢。
Sample Input 1
1
Sample Output 1
2
Hint
無
思路:
簽到題。
參考代碼:
#include<stdio.h>
int main()
{
int a;
scanf("%d",&a);
printf("%d",(a%3)+1);
return 0;
}
易錯點分析
同A題。
C題-搶紅包
Problem Description
背景
發(fā)紅包是中國春節(jié)的傳統(tǒng)習俗。每逢春節(jié)拜年,長輩都要將事先準備好的壓歲錢以紅包的形式分給晚輩,寓意好運連連。隨著互聯(lián)網(wǎng)的發(fā)展,電子紅包逐漸代替了傳統(tǒng)的紙質(zhì)紅包,微信紅包逐漸成為了一種“新年俗”。
具體描述
每年春節(jié),SLF都會在微信群上搶紅包,賺得盆滿缽滿(那是不可能的),但也因為一直守在微信上搶紅包,每年SLF都會被父母指責在飯桌上沒有和親戚朋友多聊天。這不,春節(jié)又到了,正當SLF為此而苦惱時,LWH找上門來了。
LWH自己用C語言寫了一個自動搶紅包的輔助工具,想為SLF解決煩惱,但條件是:
(1)SLF必須用5塊錢買這個工具。
(2)SLF使用該工具搶紅包時,一旦搶到的金額不小于10塊錢,就必須分給LWH 1塊錢。
但SLF覺得自己不劃算,于是LWH又提出了另一種條件:
(1)SLF免費使用這個工具。
(2)SLF使用該工具搶紅包時,一旦搶到的金額不小于5塊錢,就必須分給LWH 1塊錢。
于是SLF決定分別計算2種條件下必須給LWH的金額,并選擇給LWH其中較少的金額,但是好景不長,與SLF多次搶同一紅包的XZJ馬上發(fā)現(xiàn)了蹊蹺,并在SLF搶完第n個紅包后舉報了SLF,此后SLF的工具便失效。
由于SLF抽不出時間計算最終要給LWH的金額,便想請你幫忙設計一個程序完成這個任務。
Input
第1行,一個整數(shù)n(0<=n<=100)。
接下來n行,每行一個整數(shù)m,表示SLF使用工具搶到的金額。
Output
一個整數(shù),表示SLF最終需要給LWH的金額。
Sample Input 1
3
7
3
15
Sample Output 1
2
Sample Input 2
6
9
5
6
7
8
5
Sample Output 2
5
Hint
無
思路:
1、設置2個變量記錄2種條件下需要給出的金額,注意“記錄條件1的變量”的初始值為5(表示花費5塊錢購買輔助工具)。
2、因為搶紅包是獨立事件,事件之間互不影響,所以采用for循環(huán)結(jié)構(gòu)處理每次搶紅包操作。在每次循環(huán)中,若紅包金額不小于10,則記錄條件1的變量要加1(表示給出1塊錢);若紅包金額不小于5,則記錄條件2的變量要加1(表示給出1塊錢)。
最后取這兩個變量中的較小值輸出即可。
參考代碼:
#include<stdio.h>
int main()
{
//n是紅包個數(shù),m是每次搶到的金額
int n,m;
//輸入紅包個數(shù)
scanf("%d",&n);
//sum1、sum2分別統(tǒng)計條件1、條件2下必須給出的總金額
//sum1的初始值為5表示條件1下買輔助工具的花費
int sum1=5,sum2=0;
//采用for循環(huán)獲取每次搶紅包操作
int i;
for(i=1;i<=n;i++)
{
//輸入搶到金額
scanf("%d",&m);
//判斷條件1下紅包是否滿足要求
if(m>=10)
{
sum1=sum1+1;
}
//判斷條件2下紅包是否滿足要求
if(m>=5)
{
sum2=sum2+1;
}
}
//輸出2種條件下較小的金額
if(sum1>sum2){
printf("%d",sum2);
}
else
{
printf("%d",sum1);
}
return 0;
}
易錯點分析
1、要注意條件1的sum1的初始值應該為5。
2、這兩個條件的時間互為獨立事件,所以應該是兩條if語句判斷。
D題-球魁
Problem Description
LWH十分喜歡打籃球,天天打球的他投籃百發(fā)百中,成為了南海校區(qū)的球魁,于是他開始嘲笑不會打球的LZH。為了捍衛(wèi)自己的尊嚴,LZH進行了一個暑假的苦練,也達到了百發(fā)百中的投籃命中率,于是他向LWH挑戰(zhàn),一場球魁爭奪賽開始了。
他們打算用罰球線投籃計分的方式一決勝負,規(guī)則如下:
①首先利用骰子的點數(shù)n來決定誰先投球,若是偶數(shù),則LWH先投;若是奇數(shù),則LZH先投。
②比賽分為r輪,一人投一輪,輪流投籃。(例如:若LWH先投,則第二輪LZH投,第三輪又輪到LWH投,依此類推,直至到第r輪結(jié)束)
③由于雙方的投籃命中率都是百分百,所以每一輪他們都能投中,理論上投中一球得兩分,但由于LWH受今年籃球世界杯中國男籃的影響,他每次投球都有一個心情值L,若L是素數(shù),則他的得分仍為2分;特別地,當L為11時,他的得分變?yōu)?分;若L是合數(shù),則他的得分變?yōu)?分,特別地,當L為15時,他的得分變?yōu)?分。而LZH忙著打算法比賽沒看世界杯,所以不受影響(即每一球均為兩分)。
現(xiàn)在,他們找你作為裁判為他們計分,并判斷誰贏得比賽,而身為軟工的大學生,你準備寫個程序,讓程序來算。
Input
第一行輸入兩個整數(shù) r(1 <= r <= 2000) 和 n(1 <= n <= 6),分別代表比賽的輪數(shù)和骰子的點數(shù)。
接下來輸入一行,共 q 個正整數(shù) L,用空格隔開。其中,q 代表 r 輪中 LWH 的輪數(shù)和,L 代表心情值(2 <= L <= 100)。
說明:
若輪到 LWH 投籃,則輸入一個心情值 L;若輪到 LZH 投籃,則無需輸入。
例如,當 r = 7, n = 2 時,q 為 4。因為 LWH 先發(fā)球,則輪到 LWH 投球的輪數(shù)有第一輪,第三輪,第五輪,第七輪,共四輪;
Output
輸出一行,顯示比賽結(jié)果:若是 LWH 贏,則輸出 "lwh wins.";若是 LZH 贏,則輸出 "lzh wins.";若是平局,則輸出 "equal."
(說明:輸出引號內(nèi)的內(nèi)容,不包括引號)
Sample Input 1
7 2
11 4 2 60
Sample Output 1
lwh wins.
Hint
無
思路:
1、根據(jù)總輪數(shù)r和骰子點數(shù)n來推算出q的數(shù)值,也就是LWH投的輪數(shù)。如果n為偶數(shù)q且r為奇數(shù)則q=r/2 + 1,其余情況為q=r/2。
2、每輸入一個正整數(shù)L,判斷L是否為11、15、素數(shù)、合數(shù),然后加上相對應的分數(shù)。
參考代碼:
#include<stdio.h>
#include<math.h>
int solve(int x){//返回11、15、素數(shù)、合數(shù)對應的分數(shù)
if(x==11) return 3;
if(x==15) return 0;
if(x==2) return 2;
for(int i = 2;i<sqrt(x)+0.5;++i){
if(x%i==0) return 1;
}
return 2;
}
int main(){
int r,n,q;
int ans1,ans2;//ans1代表lwh分數(shù),ans2代表lzh分數(shù)
scanf("%d%d",&r,&n);
if(n%2==0 && r%2==1)//判斷q的值
q = r/2 + 1;
else
q = r/2;
ans1 = 0; ans2 = (r-q)*2;//求出lzh對應的分數(shù)
for(int i = 0;i<q;++i){
int L;
scanf("%d",&L);
ans1+=solve(L);
}
if(ans1==ans2) printf("equal.");
else if(ans1>ans2) printf("lwh wins.");
else printf("lzh wins.");
}
易錯點分析
1、要先判斷q的值才能正確輸入,否則會造成RE或者WA。
2、判斷L對應的分數(shù)最好寫成函數(shù),這樣代碼結(jié)構(gòu)清晰。如果寫在循環(huán)里面的話要處理好每次得到分數(shù)之后要及時continue因為11也對應素數(shù)、15也對應合數(shù)。
3、這道題輸入方式比較特殊,考察了選手們對于題意的理解和輸入格式的靈活變換。
4、這道題提交次數(shù)最多但AC率較前三道題有明顯得下降,說明這道題很好得起到了選拔的作用。
E題-性質(zhì)判斷
Problem Description
化學家 PP 在 9102 年發(fā)現(xiàn)可以將所有有機物用 26 個小寫英文字母構(gòu)成的字符串表示。并且,各種有機物對應的字符串中 aa, bb, cc, …, zz(從 a 到 z,共 26 種小寫英文字母)出現(xiàn)的次數(shù)會反映出有機物的性質(zhì)。然而,PP 并不需要具體的次數(shù),只需要根據(jù) aa, bb, cc, …, zz 在字符串中的出現(xiàn)次數(shù)將 aa, bb, cc, …, zz 排好序,PP 就可以判斷有機物的性質(zhì),你能幫她將 aa, bb, cc, …, zz 排好序嗎?
Input
輸入為一行僅由小寫英文字母構(gòu)成的字符串,長度大于等于 1 且小于等于 5000。
Output
輸出為一行,按 aa, bb, cc, …, zz 在字符串中的出現(xiàn)次數(shù)(計算出現(xiàn)次數(shù)時是可重疊的,即在字符串 "aaaa" 中,aa 出現(xiàn)了三次),從多到少,將 aa, bb, cc, …, zz 排序,不同字母間以一個空格隔開,忽略行末空格。(出現(xiàn)次數(shù)相同,則按照字典序升序排列,如 dd, ee 都出現(xiàn) 1 次,則 dd 放在 ee 前面)出現(xiàn)次數(shù)為 0 的不用輸出。(如果 aa, bb, cc, …, zz 都沒有出現(xiàn)過,則什么都不用輸出)
Sample Input 1
bbaaqccc
Sample Output 1
cc aa bb
Hint
無
思路:
1、由于匹配得是aa、bb、cc等模式串,所以只需在循環(huán)里判斷當前字符和后一個字符是否相等,需要特判一下輪到最后一個字符時不需要判斷。
2、判斷相等后用數(shù)組存儲對應模式串的個數(shù),然后對這個數(shù)組進行排序即可。
3、注意:排序的時候使用選擇排序會較好,因為使用冒泡排序或者其他排序的話需要使用結(jié)構(gòu)體。
參考代碼:
#include<stdio.h>
#include<string.h>
char str[5005];//主串
int num[26]={0};//儲存26個模式串的出現(xiàn)次數(shù)
int main()
{
scanf("%s",str);
int len=strlen(str);//主串長度
int i,j;
for(i=0;i<len-1;i++)
{
if(str[i]==str[i+1])
{
num[str[i]-'a']++;//當匹配成功時,對應的位置次數(shù)加1
}
}
int maxx,maxid;
for(i=0;i<26;i++)//由于最多在26個模式串排序,時間不長,選擇簡單的選擇排序
{
maxx=0;
for(j=0;j<26;j++)
{
if(num[j]>maxx)
{
maxx=num[j];
maxid=j;//這趟排序最大數(shù)字對應的下標
}
}
if(maxx==0)break;//出現(xiàn)次數(shù)都為0則跳出
if(i!=0)printf(" ");
printf("%c%c",maxid+'a',maxid+'a');
num[maxid]=0;//每一趟將選出下標對應的數(shù)字清零
}
return 0;
}
易錯點分析
1、考察了數(shù)組、字符串模擬、排序。
2、這道題因為匹配得是aa、bb、cc等模式串,所以開一個26長度的標記數(shù)組,則str[i]-'a'即使對應的下標,這也是常用的技巧。
3、此外,排序也需要多加注意,如果使用結(jié)構(gòu)體,這道題在排序上不容易犯錯。但如果沒有使用結(jié)構(gòu)體,最佳的方法就是選擇排序,因為好寫且簡單。
4、這道題也是進入一等獎區(qū)的選拔題目,其實題目難度上不算難但許多選手缺乏比賽解題技巧,寫代碼容易將自己給繞進去。
F題-Matrix
Problem Description
Veggie 最近深深地迷戀上了 Matrix,現(xiàn)在他手上有一個 N × N 的矩陣,矩陣中的元素都是數(shù)字,他希望可以從不同角度欣賞矩陣之美。但是 Veggie 道行尚淺,只能請求好友 SLF 幫他完成對矩陣的變換,矩陣的變換法則如下:
法則 1:將矩陣順時針旋轉(zhuǎn) 90 度,例如:
1 2 3 7 4 1
4 5 6 → 8 5 2
7 8 9 9 6 3
法則 2:將矩陣逆時針旋轉(zhuǎn) 90 度,例如:
1 2 3 3 6 9
4 5 6 → 2 5 8
7 8 9 1 4 7
法則 3:矩陣的中央元素不變,將其他元素與 "以中央元素為中心對稱的元素" 互換,例如:
1 2 3 9 8 7
4 5 6 → 6 5 4
7 8 9 3 2 1
不料 SLF 二話不說把這個差事安排給了你,現(xiàn)在請你編程幫 Veggie 完成矩陣的變換。
Input
第一行輸入正整數(shù) N(N 為奇數(shù),且1 ≤ N ≤ 25)和 M(0 ≤ M ≤ 20) 中間以空格隔開,其中 N 如題目,M 表示矩陣變換的次數(shù)。
接下來 N 行,每行輸入 N 個在 int 類型范圍內(nèi)的整數(shù),中間以空格隔開,表示矩陣的各元素。
最后 M 行,每行輸入一個整數(shù) t(1 ≤ t ≤ 3),表示要進行變換的法則編號。
Output
輸出每次變換后的矩陣,每次輸出完需要多打印一個空行。(詳情可以參照輸出樣例 1)
注意:每輸入一個變換法則編號,視為一次變換
注意:行末多余空格會影響正確答案!
Sample Input 1
3 2
1 2 3
4 5 6
7 8 9
2
3
Sample Output 1
3 6 9
2 5 8
1 4 77 4 1
8 5 2
9 6 3
Hint
無
思路:
1、推出每個變換規(guī)則對應的規(guī)律,其中(matrix代表變換后數(shù)組,temp代表原來數(shù)組):
法則一:matrix[j][n-i+1]=temp[i][j]
法則二:matrix[n-j+1][i]=temp[i][j]
法則三:matrix[n-i+1][n-j+1]=temp[i][j]
2、判斷輸入數(shù)字然后進行對應轉(zhuǎn)換即可。
參考代碼:
#include<stdio.h>
#include <string.h>
int main(){
int matrix[30][30],temp[30][30];
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;++i)
for(int j = 1;j<=n;++j)
scanf("%d",&matrix[i][j]);
for(int k = 1;k<=m;++k){
int x;
scanf("%d",&x);
memcpy(temp,matrix,sizeof(matrix));//復制函數(shù):將matrix數(shù)組內(nèi)容復制到temp數(shù)組中
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
switch(x){
case 1:
matrix[j][n-i+1] = temp[i][j];//法則1
break;
case 2:
matrix[n-j+1][i] = temp[i][j];//法則2
break;
case 3:
matrix[n-i+1][n-j+1] = temp[i][j];//法則3
break;
}
}
}
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
printf("%d",matrix[i][j]);//輸出
if(j!=n) printf(" ");//注意:最后一個數(shù)字后面不要帶空格
}
printf("\n");
}
printf("\n");
}
return 0;
}
易錯點分析
1、考察了二維數(shù)組、規(guī)律演算。
2、只要推出了對應的規(guī)律之后,這道題代碼就相當簡單。
3、如果直接暴力模擬也可以,但是代碼較長且容易出錯。
G題-簡單的RC簽到題
Problem Description
給定素數(shù)a,b,c,d,求1到n中的整數(shù)中至少能整除這4個元素中的一個的數(shù)有幾個?
Input
輸入兩行:
第一行為一個整數(shù)n(1≤n≤1e18)
第二行為四個數(shù)a,b,c,d(abc*d<1e18,數(shù)據(jù)保證a,b,c,d為互不相同的素數(shù))
Output
僅一行,輸出答案即可。
Sample Input 1
1000
2 13 17 41
Sample Output 1
575
Hint
無
思路:
1、考慮數(shù)據(jù)范圍最大到1e18,暴力枚舉會超時,所以要用容斥原理。
2、將分別整除a,b,c,d的數(shù)分為四個集合,設為A,B,C,D,我們的目標就是求A∪B∪C∪D,所以用以下公式求解:
3、所以有:A∪B∪C∪D=A+B+C+D-AB-AC-AD-BC-BD-CD+ABC+ABD+ACD+BCD-ABCD
因為A,B,C,D都是素數(shù),所以A=n/a,……,ABCD=n/(a*b*c*d),代入求解即可。
參考代碼:
#include <stdio.h>
int main(){
long long n;
scanf("%lld",&n);
long long a,b,c,d,ans = 0;
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
ans += n/a + n/b + n/c + n/d;
ans -= n/(a*b) + n/(a*c) + n/(a*d) + n/(b*c) + n/(b*d) + n/(c*d);
ans += n/(a*b*c) + n/(a*b*d) + n/(a*c*d) + n/(b*c*d);
ans -= n/(a*b*c*d);
printf("%lld",ans);
return 0;
}
易錯點分析
1、很多同學沒有注意到數(shù)據(jù)范圍,直接暴力枚舉,導致超時。
2、在寫容斥的時候容易漏掉一些情況,例如少了abc、abd等等。
3、容斥公式是奇數(shù)項相加、偶數(shù)項相減。
H題-強迫癥患者
Problem Description
cgy是一個很有強迫癥的人,他一看到小數(shù)就渾身難受。然而有一天,他碰到了這么一條只有整數(shù)和除號構(gòu)成的式子:1/2/4/16,他的強迫癥又來了,加上了括號讓式子變成了 (1/2)/(4/16)=2把它變成了整數(shù)。但是走著走著,他又碰到了一個墻上寫滿了這個風格的式子,cgy突然發(fā)現(xiàn)有些式子可以通過加括號來讓結(jié)果變?yōu)檎麛?shù),有些卻不行。但是他手邊沒有紙和筆,于是就沒有把這個想法寫下來,現(xiàn)在你能通過這一系列數(shù)字來判斷他們是否可以通過加括號變成整數(shù)么?
Input
一個整數(shù)n(n<=100)表示有幾組數(shù)據(jù)
接下來輸入m(1<=m<=10000)表示有m個數(shù)字,再下去一行輸入m個正整數(shù)(每個數(shù)字不大于100000),表示式子中的數(shù)字。
Output
對于每一行輸入,如果可以通過加括號變成整數(shù)就輸出Yes,否則輸出No。
Sample Input 1
3
3
1 2 4
4
1 5 6 9
4
1 4 2 2
Sample Output 1
Yes
No
Yes
Hint
對于樣例一中的第一組數(shù)據(jù):1/2/4 → 1/(2/4) = 2,Yes。
第二組數(shù)據(jù):1/5/6/9不能通過加括號轉(zhuǎn)化成整數(shù),No。
第三組數(shù)據(jù):1/4/2/2 → 1/((4/2)/2) = 1,Yes。
思路:
1、在除法表達式X1/X2/X3/.../Xk里,我們可以知道第一個數(shù)字一定是分子,第二個數(shù)字一定是分母。
2、其他數(shù)字我們可以通過添加括號使得它們成為分子或者分母,既然要求整除,所以讓它們成為分子更好,因為這樣就可以盡可能得整除分母(也就是第二個數(shù)字)。
3、所以我們只需判斷X1*X3*...*Xk是否整除X2即可。
4、考慮到最多有(1e4 - 1)個不大于1e5數(shù)字的相乘,這樣會爆掉longlong的存儲范圍,所以我們考慮可以讓當前分母除于每個分子與它的最大公約數(shù)gcd,只要最后分母為1就表示可以整除。
5、最后需要注意一點就是需要特判m==1的情況,如果m為1就直接輸出"Yes"。
參考代碼:
#include <stdio.h>
int gcd(int x,int y){//求最大公約數(shù)gcd
return y==0?x:gcd(y,x%y);
}
int main(){
int n,m;
scanf("%d",&n);
while(n--){
int x,x2;
scanf("%d",&m);
if(m==1){//特判m==1的情況
scanf("%d",&x);
printf("Yes\n");
continue;
}
scanf("%d%d",&x,&x2);
x2 /= gcd(x,x2);//x2除于gcd(x,x2)
for(int i = 2;i<m;++i){
scanf("%d",&x);
x2 /= gcd(x,x2);//x2不斷除于gcd(x,x2)
}
if(x2==1) printf("Yes\n");//x2==1表明最后式子能夠整除
else printf("No\n");
}
return 0;
}
易錯點分析
1、有的同學已經(jīng)想出整除表達式可以使得X2作為分母,其它數(shù)字相乘作為分母了,但是沒有考慮到其他數(shù)字相乘會爆掉longlong,痛失AK的機會。//手動滑稽
2、這道題加了一個Hack:m==1,這個需要特判一下,不然會WA或者RE。
3、這道題加強了數(shù)據(jù),所以用JAVA大數(shù)或者Python暴力相乘會TLE。
寫到最后:
1、特別感謝CGY來監(jiān)賽和講題解。//邊緣ob的感覺真好hhh
2、這次AK杯比賽的結(jié)果我們還是比較滿意的,結(jié)果也基本符合我們之前的預期。
排名的梯度比較明顯,也可能是因為今年題目變多了,大家選擇的余地會大一點。
3、可惜rjl只差一點點就能完成AK成就,看來明年比賽名應該要改成《不能AK的AK杯》hhh。