2018年江西理工大学C语言竞赛初级组第一、二套题解
比赛时发现好多人喜欢多输出些东西,这反而会答案错误。
题目说输出什么就输出什么,不要多输出任意东西就行。
第一套:
A 整数序列中两个相邻的数,如果后面的数小于前面的数,则称这两个数值构成了一个逆序对。例如,整数序列10,4,16,8,21,18,9中包含了4个逆序对。从键盘上输入n(n≤1000)个由空格分隔的整数,编程输出其中包含的逆序对的数量。
签到题。
1 #include <stdio.h> 2 const int N = 1010; 3 int a[N]; 4 int main() { 5 int n, ans = 0; 6 scanf("%d", &n); 7 for(int i = 1; i <= n; i ++) scanf("%d",&a[i]); 8 for(int i = 1; i < n; i ++) if(a[i] > a[i+1]) ans++; 9 printf("%d\n",ans); 10 return 0; 11 }
B 最近小S不高兴了,所以她就想画圈圈,有大有小的。而现在她想让你也画圈圈了^_^。
大小为3的圈圈是,大小为4的圈圈是,大小为5的圈圈是,依次类推。
接着送分题
1 #include <stdio.h> 2 3 int main() { 4 int n; 5 scanf("%d", &n); 6 for(int i = 1; i <= n; i ++) { 7 for(int j = 1; j <= n; j ++) { 8 if((i == 1 || i == n) && (j == 1 || j == n)) printf("*"); 9 else if(i == 1 || i == n || j == 1 || j == n) printf("#"); 10 else printf("*"); 11 } 12 printf("\n"); 13 } 14 return 0; 15 }
C 小明现在有x元,现在想买一件y(y ≤ x)元的物品,商店里有五种货币,100元、20元、10元、5元、1元无限张,服务员会以最小的数量找零钱。问小明用x元买了一件y元的物品后找了多少张零钱。
第一套和第二套都有这题,不过第一套的是没有50元,第二套的是没有100元。
贪心,每次找最大的货币,这样就能使的零钱数量最少。
1 #include <stdio.h> 2 3 int main() { 4 int x, y, ans = 0; 5 scanf("%d%d", &x, &y); 6 x -= y; 7 ans += x/100; x %= 100; 8 ans += x/20; x %= 20; 9 ans += x/10; x %= 10; 10 ans += x/5; x %= 5; 11 ans += x/1; 12 printf("%d\n",ans); 13 return 0; 14 }
D 现在的编程越来越多了,比如C、C++、Java、Python、C#、PHP等等。现在给定n种编程语言,每种语言还会给一个[1,n]之间的随机值,保证不重复。现在让你按随机值从小到大排序,然后输出对应的语言。
输入:
第一行输入一个整数n(1≤ n ≤ 20)
接下来n行,每行有一个字符串和一个随机值,字符串表示一种语言,长度不超过20.随机值范围为[1,n]
用结构体储存编程语言的名字和随机值。
n最大才20,随便用种排序就能过。
1 #include <stdio.h> 2 struct Nod{ 3 char s[22]; 4 int id; 5 }e[22], tmp; 6 7 int main() { 8 int n; 9 scanf("%d",&n); 10 for(int i = 1; i <= n; i ++) { 11 scanf("%s%d",e[i].s,&e[i].id); 12 } 13 for(int i = 1; i <= n; i ++) { 14 for(int j = i+1; j <= n; j ++) { 15 if(e[i].id > e[j].id) { 16 tmp = e[i]; 17 e[i] = e[j]; 18 e[j] = tmp; 19 } 20 } 21 } 22 for(int i = 1; i <= n; i ++) printf("%s\n",e[i].s); 23 return 0; 24 }
E 有一个四边形,现在需要求它的面积。
需要注意的是有凸凹边形。
将四边形分成两个三角形,计算两个三角形面积的和就是答案。
但由于用凹边形,将四边形分成两个三角形时,有两种答案。在纸上画下这两个分法。其实不难得出面积最小的那个就是四边形的正确面积。
1 #include <stdio.h> 2 #include <math.h> 3 4 double min(double x, double y) { return x>y?y:x;} 5 double x[4], y[4]; 6 7 double dist(double x1, double y1, double x2, double y2) { 8 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 9 } 10 double getArea(double a, double b, double c) { 11 double p = (a+b+c)/2.0; 12 return sqrt(p*(p-a)*(p-b)*(p-c)); 13 } 14 int main() { 15 for(int i = 0; i < 4; i ++) scanf("%lf%lf",&x[i], &y[i]); 16 double l1, l2, l3, l4, l5, l6; 17 l1 = dist(x[0],y[0],x[1],y[1]); 18 l2 = dist(x[1],y[1],x[2],y[2]); 19 l3 = dist(x[2],y[2],x[3],y[3]); 20 l4 = dist(x[3],y[3],x[0],y[0]); 21 l5 = dist(x[0],y[0],x[2],y[2]); 22 l6 = dist(x[1],y[1],x[3],y[3]); 23 double area1 = getArea(l1,l2,l5)+getArea(l3,l4,l5); 24 double area2 = getArea(l1,l4,l6)+getArea(l2,l3,l6); 25 printf("%.3lf\n",min(area1,area2)); 26 return 0; 27 }
F 给定一个区间[l, r],从l至r之间的所有数依次转换成16进制然后连在一起,接着再转换成10进制,最后再对15取模。
将区间内的数字拼接成16进制,其实16中的每一位都可以转化成a*16^b的其实。而16^b % 15 == 1 。这样就是对区间内的数求和在对15取模。
以样例为例,703710 = 10*16^4+11*10^3+12*16^2+13*16^1+14*10^0。16^4%15==1 10^3%15==1 10^2%15==1 10^1%15==1 10^0%15==1
所以答案就是(10+11+12+13+14)%15 == 0
1 #include <stdio.h> 2 3 int main() { 4 int l, r, ans = 0; 5 scanf("%d%d",&l,&r); 6 for(int i = l; i <= r; i ++) { 7 ans = (ans+i)%15; 8 } 9 printf("%d\n",ans); 10 return 0; 11 }
上面的复杂度高了。 由于%15 所以每16个数就一个循环。(1+14)%15=0 (2+13)%15=0...(7+8)%15=0,这样那些循环的都是0,只要计算那些没有循环的就行了。这样循环最多才15次。
1 #include <stdio.h> 2 3 int main() { 4 int l, r, ans = 0; 5 scanf("%d%d", &l, &r); 6 r = r-(r-l)/15*15; 7 for(int i = l; i <= r; i ++) { 8 ans = (ans+i)%15; 9 } 10 printf("%d\n",ans); 11 return 0; 12 }
第二套
A 和第一套一样。
B 又一道签到题。判断下位置就行了。
1 #include <stdio.h> 2 3 char s[4][16]; 4 5 int main() { 6 char ch; 7 for(int i = 0; i < 4; i ++) scanf("%s",s[i]); 8 for(int i = 0; i < 3; i ++) { 9 for(int j = 0; s[i][j]; j ++) { 10 if(s[i][j] == s[3][0]) { 11 printf("%d %d\n",i+1,j+1); 12 } 13 } 14 } 15 return 0; 16 }
C 和第一套的C题解题思路一样。
1 #include <stdio.h> 2 3 int main() { 4 int x, y, ans = 0; 5 scanf("%d%d", &x, &y); 6 x -= y; 7 ans += x/50; x %= 50; 8 ans += x/20; x %= 20; 9 ans += x/10; x %= 10; 10 ans += x/5; x %= 5; 11 ans += x/1; 12 printf("%d\n",ans); 13 return 0; 14 }
D 数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3×3)内的数字均含1-9,不重复。当然,肯定不会让你用程序完成没填好的数独的。现在给你一个9×9填满了数的格子,想让你检查一下是不是符合数独的定义。比如下图是符合数独的定义的。
判断下每9列,每9行和每9个粗线是否是1-9都出现了一次就行。
1 #include <stdio.h> 2 #include <string.h> 3 char s[10][10]; 4 bool vis[10]; 5 bool ok1(int x, int y) { 6 memset(vis, 0, sizeof(vis)); 7 for(int i = x; i < x+3; i ++) { 8 for(int j = y; j < y+3; j ++) { 9 if(vis[s[i][j]-'0']) return false; 10 vis[s[i][j]-'0'] = 1; 11 } 12 } 13 return true; 14 } 15 bool ok2(int pos, int flag) { 16 memset(vis, 0, sizeof(vis)); 17 if(flag == 1) { 18 for(int i = 1; i <= 9; i ++) { 19 if(vis[s[pos][i]-'0']) return false; 20 vis[s[pos][i]-'0'] = 1; 21 } 22 } else { 23 for(int i = 1; i <= 9; i ++) { 24 if(vis[s[i][pos]-'0']) return false; 25 vis[s[i][pos]-'0'] = 1; 26 } 27 } 28 return true; 29 } 30 int main() { 31 bool flag = true; 32 for(int i = 1; i <= 9; i ++) scanf("%s",s[i]+1); 33 for(int i = 1; i <= 9; i ++) { 34 if(!ok2(i,1) || !ok2(i,0)) flag = false; 35 } 36 for(int i = 1; i <= 7; i += 3) { 37 for(int j = 1; j <= 7; j += 3) { 38 if(!ok1(i,j)) flag = false; 39 } 40 } 41 if(flag) printf("YES\n"); 42 else printf("NO\n"); 43 return 0; 44 }
E 现在有n个棒棒糖,对于每个棒棒糖都有两个数Ai,Bi,Ai表示棒棒糖的体积,Bi表示棒棒糖放入水中每秒融化的体积。然后有m个装满水的杯子,每个杯子有且仅能放一个棒棒糖,放完一个棒棒糖后就不能再放其它棒棒糖了,在第0s时就应该将选择的棒棒糖全放在杯子里。问怎么选择棒棒糖使的第s秒到第t秒中间(包括s和t)融化的棒棒糖体积之和最大。
先计算每根棒棒糖在[s,t]间能融化的棒棒糖体积,按从大到小排下序,去前min(n,m)个体积最大的和就是答案了。
1 #include <stdio.h> 2 #define ll long long 3 4 ll res[1010]; 5 int min(int x, int y) {return x>y?y:x;} 6 int max(int x, int y) {return x>y?x:y;} 7 int main() { 8 int n, m, s, t, a, b; 9 scanf("%d%d%d%d",&n, &m, &s, &t); 10 for(int i = 1; i <= n; i ++) { 11 scanf("%d%d", &a, &b); 12 res[i] = min((t-s+1)*b, max(0,a-(s-1)*b)); 13 } 14 for(int i = 1; i <= n; i ++) { 15 for(int j = i+1; j <= n; j ++) { 16 if(res[i] < res[j]) { 17 int tmp = res[i]; 18 res[i] = res[j]; 19 res[j] = tmp; 20 } 21 } 22 } 23 ll ans = 0; 24 for(int i = 1; i <= min(n,m); i ++) ans += res[i]; 25 printf("%lld\n",ans); 26 return 0; 27 }
F 给定两个整数a和b(保证所有数据不包含前导0),现在你可交换a里面任意两个数字,得到一个新的a,使得a为小于等于b的最大整数,例如给定a:1234,b:5555,得到4321。如果找不到小于等于b的最大a,则输出-1。(输出也必须保证不包含前导0,例如0123是不合法输出)。
一开始就将a组成最小的数。然后两次循环,让两两之间的数都交换下位置,看否还是小于等于b,如果是的话就留下来,不是的话就换回来。因为一开始就是最小的数(即前面的≤后面的),所以每次交换成功后都会使得数字变大些。
最后看a是否还是≤b 是的话就输出答案,否则输出-1.
1 #include <algorithm> 2 #include <iostream> 3 #include <string.h> 4 #include <stdio.h> 5 #define ll long long 6 using namespace std; 7 char s[20]; 8 ll solve() { 9 ll ans = 0; 10 for(int i = 0; s[i]; i ++) ans = ans*10+s[i]-'0'; 11 return ans; 12 } 13 14 int main() { 15 ll a, b; 16 scanf("%s%lld", &s, &b); 17 int len = strlen(s); 18 sort(s,s+len); 19 for(int i = 0; i < len; i ++) { 20 for(int j = i+1; j < len; j ++) { 21 swap(s[i], s[j]); 22 if(solve() > b) swap(s[i], s[j]); 23 } 24 } 25 a = solve(); 26 if(a <= b) printf("%lld\n",solve()); 27 else printf("-1\n"); 28 return 0; 29 }