20-21(2)第0次线上赛题解
本次题解部分参考CST20001做的解析
我觉得我的排版好看一点(bushi)
希望各位是看懂了代码自己打而不是复制粘贴,提交(doge)
1:签到题-5
题意:
有n名同学及其学号,n-1名已签到,求未签到的同学的学号。
题解:
方法一(最巧妙的一个方法,来自涂涂):
用两次for循环,第一次求和,第二次作差,结果就是那名同学的学号了。
方法二(来自IST20013 & tql):
map容器 key-value学号不重复>set>s. erase>输出
(听不懂对吧,我也不会!)
方法三(我的凡人做法):
补充知识:
1:关于堆和栈(引用涂涂的话):
(1)直接声明的为栈变量,由系统自动分配内存和释放,为局部变量,在退出本函数后,自动释放。
(2)new出来的是指针变量,存储在堆上,在退出本函数后如果没有执行 delete ,将会发生内存泄漏。建议转化为全局变量。
2:关于 sort 排序函数(引用CSDN博客资料):
(1)格式: sort('数组名,即数组首地址','数组首地址+数组元素个数n');
(2)sort 排序默认为升序,头文件为 #include<algorithm> ,效果类似于冒泡、选择排序。
方法四(来自一名学长):
使用异或,例如2^3^2=3,重复出现就会被消掉(消消乐bushi)
上板子(方法三):
#include<iostream> #include<stdio.h> #include<algorithm>//sort函数的头文件 using namespace std; int p1[100005]; int p2[100005]; int main() { int n; cin >> n; for (int i = 0;i < n;i++) { cin >> p1[i]; } sort(p1, p1 + n); for (int i = 0;i < n - 1;i++) { cin >> p2[i]; } sort(p2, p2 + n - 1); for (int i = 0;i < n;i++) { if (p1[i] != p2[i]) { cout << p1[i] << endl; break; } } return 0; }
2:区间并集
题意:
存在 n 个区间:a1、a2、…… 、an。求 a1 ∪ a2 ∪ a3 ∪ …… ∪ an。
题解:
方法一(来自CST20001):
结构体存储每一次输入的L、R(左右端),然后sort排序,排序规则看compare,然后记录第一个L、R为l、r,后面有L大于记录的r时输出存储的l、r,存储新的L、R,如果后面的L不大于记录的r则合并合集,取俩合集(存储的l、r和该次的L、R)中最小的左端为l和最大的右端为r。
上板子(方法一):
#include<iostream> #include<algorithm> using namespace std; typedef long long int ll; struct qj { ll L; ll R; };//结构体,类似我们接下来要学的class qj s[100005]; bool compare(qj a,qj b) { if(a.L==b.L) { return a.R<b.R; } return a.L<b.L; }//他自己做的一个排序函数 int main() { ll n; cin>>n; for(ll i=1;i<=n;i++) { cin>>s[i].L>>s[i].R; } sort(s,s+n+1,compare); ll l=0,r=0; for(ll i=1;i<=n;i++) { if(i==1) { l=s[i].L; r=s[i].R; } else { if(s[i].L>r) { cout<<l<<" "<<r<<endl; l=s[i].L; r=s[i].R; } else { if(s[i].R>r) { r=s[i].R; } } } } cout<<l<<" "<<r<<endl; return 0; }
方法二:
一维数组分别排序。
上板子(方法二):
#include<iostream> #include<cmath> #include<algorithm> #define ll long long int using namespace std; ll p1[100005]; ll p2[100005]; int main() { int n; cin >> n; for (int i = 0;i < n;i++) { cin >> p1[i] >> p2[i];//将最小值与最大值分别存在两个数组中 } sort(p1, p1 + n);//对两个一维数组分别排序 sort(p2, p2 + n); for (int i = 0;i < n;i++) { if (p2[i] < p1[i + 1]) cout << p1[i] << " " << p2[i]<<endl; else p1[i + 1] = min(p1[i], p1[i + 1]), p2[i + 1] = max(p2[i], p2[i + 1]); } cout << p1[n-1] << " " << p2[n-1] << endl; return 0; }
3:特殊的01串
题意:
我们定义一个字符串是特殊的01串:
1.空串是特殊的01串。
2.仅由字符 0 和 1 构成且任意两个相邻的字符不都为 1。
现在请你构造一个长度为 n 的特殊的01串,请问你可以构造多少个?
题解:
打草稿,找规律,然后你就会发现这考的是斐波那契数列,所以用数组存储前面的结果,递推。
补充知识:
memset 函数(参考CSDN博客):
(1)主要作用:赋初始值、 清空数组/变量。
(2)格式:memset(‘数组/变量名’, ‘数字或字符’, size) 。
(3)memset 以字节为单位进行赋值,所以只能赋值0,-1,'d'(字符),'\0'(转义字符)。
上板子:
#include<iostream> #include<cstring> #define mod 998244353 using namespace std; int ans[1000005]; int main() { memset(ans,0,sizeof(ans)); ans[0]=1;ans[1]=2;ans[2]=3;ans[3]=5; for(int i=4;i<=1000005;i++) { ans[i]=(ans[i-1]+ans[i-2])%mod; } int T; cin>>T; for(int f=1;f<=T;f++) { int n; cin>>n; cout<<ans[n]<<endl; } return 0; }
4:公因数-2
题意:
有 n 个数字,求它们的公共质因数。
输出要求:
按从小到大的顺序依次输出这 n 个数字的公共质因数,每两个数字之间用空格隔开,最后一个数字后面没有空格。
如果它们没有公共质因数则输出 No
。
最后换行。
题解:
方法一:
运用埃氏筛 / 线性筛出1e5以下的质数(方法详解可见我的《 2020级cpp机考模拟题A卷-#题解2 》),将所有质数排序,再循环判断每个质数是否满足为每个数的公因数
上板子(方法一):
#include<iostream> #include<cmath> #define ll long long int using namespace std; const int M = 100002; bool b[M]; int p[1000], cnt = 0; int num[M]; void k() { for (int i = 2; i < M; i++)//1不是素数,所以b[1]=0. { b[i] = 1;//先当他们全是素数,下面再用循环判断 } for (int i = 2; i <= sqrt(M); i++) { if (b[i]) { cnt++; p[cnt] = i; for (ll j = (ll)i * i; j < M; j += i) { b[j] = 0; } } } } int main() { k(); int n, count = 0; cin >> n; bool o; for (int i = 1;i <= n;i++) { cin >> num[i]; } for (int i = 1;i <= cnt;i++) { o = 1; for (int j = 1;j <= n;j += 2) { if (num[j] % p[i] != 0 || num[j + 1] % p[i] != 0) { o = 0; break; } } if (o == 1) { if (count != 0)cout << " "; cout << p[i]; count++; } } if (count == 0)cout << "No"; cout << endl; return 0; }
方法二:
从小到大排序这n个数字——拿a[0](即最小值)找小于等于它的质数——得到质数——判断是不是公因数——是——输出。
上板子(方法二):
#include<iostream> #include<cmath> using namespace std; int num[100005]; bool zhi(int x)//判断质数 { for (int i = 2;i <= sqrt(x);i++) { if (x % i == 0)return false; } return true; } int main() { int n; cin >> n >> num[0]; int mi = num[0];//记录最小值 for (int i = 1;i < n;i++) { cin >> num[i]; if (num[i] < mi) mi = num[i]; } bool ans = 0;//用于判断是否存在公因数 for (int j = 2;j <= mi;j++) { int cnt = 0;//记录满足为公因数数量 if (zhi(j)) { for (int i = 0;i < n;i++) { if (num[i] % j)break; else cnt++; } if (cnt == n) { if (ans)cout << " "; else ans = true; cout << j; } } } if (ans == false)cout << "No"; cout << endl; }
5:WSAD
题意:
罗少在玩一个游戏,用 W S A D 分别控制角色进行 上 下 左 右 移动,我们可以把地图看作一个二维平面,罗少初始站在原点,现在他操作了 n 次,请你输出他的位置。
题解:
真正的签到题
上板子:
#include<iostream> #include<cstring> using namespace std; int main() { int n; cin >> n; int x, y; string t; while (n--) { cin >> t; x = 0, y = 0; for (int i = 0;i < t.length();i++) { char c = t[i]; if (c == 'W') y++; else if (c == 'S') y--; else if (c == 'A') x--; else if (c == 'D') x++; } cout << x << " " << y << endl; } return 0; }
6:数组的贡献值
题意:
给定一个长度为 n 的数组,定义数组的贡献值为数组中 每个数首次出现的位置 * 每个数出现的次数 之和(相同的数字只计算一次)。
例如:1 2 2 3 1,数字 1 首次出现的位置是 1,总共出现了 2 次,所以提供 1 * 2 = 2 的贡献值,数字 2 是 2 * 2 = 4,数字 3 是 4 * 1 = 4,因此这个数组的贡献值为 2 + 4 + 4 = 10。
但很显然这样是难不倒罗少的,所以附加了一个条件,你可以任意改变数组中数的位置,问改变后数组最大的贡献值是多少?
题解:
https://blog.csdn.net/IST20008/article/details/114495272
制作:BDT20040
祝大家学习进步,出题组早日秃头(bushi)