- 第三届SWPUACM新生赛-正式赛
招新正式赛题解
- 2021-10-25 19:42:15 @
A. Arknights(1)
考点
字符串
题意
T组输入,每组输入包含一个字符串S1和一个字符w,输入字符w在字符串S1出现的次数,如果为二则额外输出一行“学长好帅我好爱>v<”。
思路
字符串签到题没啥好讲的,注意一下输入有个空格
CODE
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<ctime>
using namespace std;
const int N=1e5+5;
char s1[N];
char w;
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%s %c",s1,&w);
int fg=0;
int len=strlen(s1);
for(int i=0;i<len;i++){
if(s1[i]==w){
fg++;
}
}
printf("%d\n",fg);
if(fg==2)
printf("学长好帅我好爱>v<\n");
}
return 0;
}
B. Heroic rescue
考点
二进制、位运算,模拟
题意
给你一个数字X,然后我们在它的二进制下可以进行两个操作:
- 如果X当前在二进制下有偶数个1那么我们将最低位上的值和1进行异或操作
- 如果X当前在二进制下有奇数个1那么我们将最高位上的值和1进行异或操作
至少通过多少次操作能让X变为0
思路
直接暴力模拟即可,因为数据才1e10,也就是最多33位,我们可以直接用二进制的左移来枚举,当然也可以先将这个数转化成二进制存在数组里面,然后再逐步操作
CODE
#include<bits/stdc++.h>
#include<cstdlib>
using namespace std;
#define ll long long
ll n,t;
ll slove(ll k) {
ll ans = 0;
ll kk = 0;
for(ll j = 0;j < 34; ++j) {//计算1的个数
if(k &(1LL<<j)) kk++;
}
if(kk&1) {//如果有奇数个我们先处理一次,然后1的个数就会变成偶数个
for(ll j = 34;j >= 0; --j)//找到最高位
if(k & (1LL<<j) ) {
k -= (1LL<<j);
ans++;
break;
}
}
for(ll i = 34LL;i >= 0; --i) {//逐步模拟
if(k & (1LL<<i)) {//如果当前位置为1那么我们就进行操作
if(k & 1) k--;//如果低位为1的话那么我们就先让k的值-1 =》 1 xor 1 = 1
else k++;//如果低位为0的话那么我们就先让k的值+1 =》 1 xor 0 = 0
ans++;
if(k == 0) break;//如果为0跳出
k -= (1LL<<i);//处理高位情况
ans++;
if(k == 0) break;//如果为0跳出
}
}
return ans;//返回操作次数
}
int main()
{
scanf("%lld",&t);
while(t--) {
scanf("%lld",&n);
printf("%lld\n",slove(n));
}
return 0;
}
C. 僵尸博士的渴望
考点
字符串
我觉得是简单题 不知道为啥新生赛的时候大家都没写怎么出来,可能是字符串这块还没咋学,下面放简单好写代码 这是我用c写的
思路
题意:
每凑齐26个字母就出现一次,那么出现次数就是26个字母中拥有最少的那个。将字符串存进数组,然后记得另创一个b数组来存各个字母拥有的次数。将字符串从头到尾遍历,每遍历一个字母就将b数组对应下标为str[i]-'A'的位置的数加一,最后统计一下出现次数最少的字母的次数。 注意
读完n后要getchar();下一个表示回车的字符,不然会读进字符串。
CODE
#include<stdio.h>
#include<string.h>
char str[1000005];
int main()
{
long long n,min=1e6+1;
int b[30]={0};
scanf("%lld",&n);
getchar();
scanf("%s",str);
int l=strlen(str);
for(int i=0;i<l;i++)
{
b[str[i]-'A']++;
}
for(int i=0;i<26;i++)
{
if(min>b[i])min=b[i];
}
printf("%lld",min*n);
return 0;
}
下面的是C++版本
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map <char,ll> ma;
int main(){
ll n,ans=0x3f3f3f3f;
string s;
cin>>n>>s;
for(int i=0;i<s.size();i++) ma[s[i]]++;
for(int i=0;i<26;i++) ans=min(ma['A'+i],ans);
cout<<ans*n;
return 0;
}
D. 谁是卷王?
考点
模拟
题意
按照描述找到学习成绩和综合成绩排在第一的同学,如果是同一个人则这个人是卷王否则不是。
思路
这是一个模拟题,模拟题的特点就是比较绕,难度并不大,考细心程度和阅读理解能力吧,这个题对于新手而言是比较毒瘤的。接到出题任务的时候,我就分到了模拟题,然后。。。。。。为了让大家有游戏体验,我又重新出了一个~ 这个题大概就分为三步:首先。计算学习成绩。接着,计算综合成绩。最后查找两项成绩的最大值,若是同一个人,则这个人就是“卷王”。否则,卷王就不存在。所有成绩的计算公式都在题目中给出了的哦!
CODE
#include<iostream>
using namespace std;
double a[10005],b[10005],c[10005],gpa[10005],x,res[10005],sum;
double f(double x){
if(x>=60)return (x-60)/10+1;
return 0.0;
}
int main(){
int n,m,ansx,ansy;
double maxx=0,maxy=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>m;
sum=0;
for(int j=0;j<m;j++){
cin>>a[j]>>b[j];
c[j]=f(b[j]);
gpa[i]+=(c[j]*a[j]);
sum+=a[j];
}
gpa[i]/=sum;
cin>>x;
if(gpa[i]>=1)gpa[i]=gpa[i]*10+50;
else gpa[i]=gpa[i]*60;
res[i]=gpa[i]*0.6+x;
if(res[i]>maxx){
maxx=res[i];
ansx=i;
}
if(gpa[i]>maxy){
maxy=gpa[i];
ansy=i;
}
}
if(ansx==ansy)cout<<ansx+1<<"号同学是卷王";
else cout<<"大家还不够卷,要加油哦";
return 0;
}
E. 游程编码
考点
字符串
思路
这个题是一个字符串问题。对字符串处理对于新手来说也是不容易的,过的人还不少,大家还是挺不错的。为了降低难度,提前给出了字符串的长度,保证数字只占一位。相信大家经过练习,以后做这个题就会变得得心应手了~
CODE
#include<stdio.h>
#include<string.h>
int main() {
char a[120],s[120];
int l1,i,j=0;
scanf("%d\n",&l1);
gets(a);
for (i=0;i<strlen(a);i++) {
int ii=1;
while (a[i]==a[i+ii]) {
ii++;
}
s[j]=ii+48;
j++;
s[j]=a[i];
j++;
i=i+ii-1;
}
printf("%d\n",strlen(s));
puts(s);
return 0;
}
F. Land Overseer
考点
数学
思路
这个题目要我们找到经过两个圆的最小距离之和,首先得理解清楚题意,只要经过了那个圆的范 围,那么就算通过了这个圆,根据题目给出的样例,大家自己画个图(因为我懒所以就不画了),路线应该是这样的,首先通过圆心在第一象限的圆的正下方(正对圆心的下方的那个圆的边界点),然后我们需要求此时到另一个圆的最小距离,那么就是把我们找到的第一个点和第二个圆心相连,然后只需要减去一个R就能得到样例给出的数据,可是实际上并不这么简单,因为如果当第一个圆与x轴相交时,算法就不一样的,路径应该是直接从原点开始沿x轴直接到达圆心位于x轴上圆的最左边的点,那么计算的方法应该就是s=2∗a−Rs=2*a-Rs=2∗a−R
下面直接上代码:
CODE
#include<stdio.h>
#include<math.h>
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
double a,b,r;
scanf("%lf%lf%lf",&a,&b,&r);
double s3;
if(b-r>0)
{
double s1=sqrt(a*a+(b-r)*(b-r));
s3=2*s1-r;//这是第一种情况时的计算方法
}
else
s3=2*a-r;
printf("%.2lf\n",s3);
}
return 0;
}
G. 24点
考点
模拟
思路
扑克牌的大小区间是【1,13】,取三个数、两个运算符。 对于除号:要想得到24点,绝对不可能出现两个除号(/)的情况,所以只有ab/c的这种情况(如果ab=24了,且c=1,那我们可以直接用abc来代替ab/c)。这里要注意数据类型,如果三个数都是int类型,对于(1111/5)的运算是可以得到24的,但是在实际运算中,这样算就是错的。(所以数据没出好,给你们捡漏了)。而如果都是double类型,就不会出现这种情况。 对于乘号:情况就比较多了,可以两个先加减再乘,也可以先乘再加减,也可以两个都是乘号。这里要注意如果是两个数先减,要取绝对值abs()。 对于加号和乘号,没什么好说的,没有两个减号,但可以有两个加号。
CODE
#include<bits/stdc++.h>
using namespace std;
int main(){
double a,b,c;
int n;
cin>>n;
for(int i = 0;i<n;i++){
cin>>a>>b>>c;
if(a+b+c==24) printf("YES\n");
else if(a*b*c==24) printf("YES\n");
else if(a+(b*c)==24) printf("YES\n");
else if(b+(a*c)==24) printf("YES\n");
else if(c+(b*a)==24) printf("YES\n");
else if((b*c)-a==24) printf("YES\n");
else if((a*c)-b==24) printf("YES\n");
else if((b*a)-c==24) printf("YES\n");
else if(b+c-a==24) printf("YES\n");
else if(a+c-b==24) printf("YES\n");
else if(b+a-c==24) printf("YES\n");
else if(a*(b+c)==24) printf("YES\n");
else if(b*(a+c)==24) printf("YES\n");
else if(c*(b+a)==24) printf("YES\n");
else if(a*b/c==24) printf("YES\n");
else if(a*c/b==24) printf("YES\n");
else if(b*c/a==24) printf("YES\n");
else if(abs(b-c)*a==24) printf("YES\n");
else if(abs(a-c)*b==24) printf("YES\n");
else if(abs(b-a)*c==24) printf("YES\n");
else cout<<"NO"<<endl;
}
return 0;
}
H. 善良的牛肉好
考点
二分、思维
题意
题意就是说这个题的输入和善良的dumpile的输入搞混了,意思就是这个题的输入就是dumpile的答案,dumpile的输入就是这个题的答案,那我们怎么知道dumpile的输入呢。 根据题的信息我们知道这个这个答案是一个数字且范围在(1,1000)闭区间。
思路
因为知道数据范围,而且不大,那我们就可以想到二分来解决,怎么二分呢我举个例子
int x;
scanf("%d",&x);
if(x>500)while(1);
这里我们输入一个数x,假如这个x大于500就会while(1)死循环,那么你提交返还的结果是超时(TLE),假如这个数不大于500他就不会死循环那你提交就会返还错误(WA),那想到这里就很简单了,就在dumpile那个题根据返还结果二分就好了。
小彩蛋:此题答案是206,此题题号为2002,是牛肉好对象生日。
I. 善良的dumplie
考点
二分、思维
题意
此题和善良的牛肉好题意差不多,本身这俩就是联动题,那看完了牛肉好,也应该知道dumpile该怎么做,区别就是dumpile的答案是仅包含小写字母长度为3的字符串。
思路
和牛肉好一样同样是二分,那怎么二分字符串呢,因为每个字符都有对应的ASCLL码,所以我们可以根据这个码来二分,但你要是不知道不会也可以通过枚举来试,下面展示一下枚举的例子。
char s[10];
scanf("%s",&s);
if(s[0]=='a')while(1);
通过这样的方法我们也可以知道输入的字符串是啥,具体就不赘述了思路和牛肉好一样。
小彩蛋:此题答案是"fpp",是dumpile对象的名字
J. 深海前行记
考点
思维
题意
给定两个整数n和m,表示使用技能次数(使用技能可以照亮周围)和路段长度(起点坐标为0),然后给出n个使用技能的位置,让你输出照射整个路段要求照射的最小距离。
思路
光照是发散的,在直线情况的话,也就是两边发散的 要保证路径全部照亮,也就是两两深海明珠间距都被照亮 则设一个明珠照亮距离为x,两相邻坐标为a[i],a[j] (j=i+1) 那么有 2*x>=a[j]-a[i] 因为坐标是排好序的,那么遍历一遍所有坐标即可 需要注意的是首尾两点需要特别处理一下 也即x>=a[0]-0且x>=m-a[n-1] 最后输出保留两位小数即可
CODE
#include <bits/stdc++.h>
using namespace std;
#define N 2021
typedef long long ll;
ll n, m;
ll a[N];
void solve()
{
for (int i = 0; i < n; ++i)
cin >> a[i];
ll ans = max(a[0] - 0, m - a[n - 1]), fans = 0;
//需要考虑到初始和末端的位置
for (int i = 0; i < n-1; ++i)
fans = max(fans, a[i + 1] - a[i]);
cout << fixed << setprecision(2) << max(ans / 1.0, fans / 2.0) << endl;
}
int main()
{
cin >> n >> m;
solve();
return 0;
}
K. 飞行执照
考点
物理
题意概述
带着风之翼滑行,风之翼会提供升力,荧视为质点处理。以一定的初速度,于原点飞出去。
飞行通过半径为 1 光圈即算。最后通过光圈数占总光圈数60%及以上输出Yes否则输出No。
题意分析
不难看出,这是一个平抛运动:
1.有初速度 2.中间过程受力恒定(忘了写忽略空气阻力,抱歉)
平抛运动就要考虑速度分解(刚读完高中的你们比我厉害吧 /狗头)。我们建立一个坐标系,以出发点为原点,速度方向为 x 轴正方向,下落方向为 y 轴正方向。
对速度做分解,用 x 计算下落总时长,并且利用这个时长通过时间位移公式得出下落高度,下落高度与光圈中心位置的差值小于等于 1 即可通过该光圈。
这个题还有些细节问题,欢迎私聊我讨论
可行代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
double a = (45.0 * 9.8 - 300) / 45;
int F(int x, int y, double v) {
double tt, h;
tt = 1.0 * (double)x / v;
h = 1.0 * a * tt * tt / 2.0;
if (fabs(h-y) <= 1)
return 1;
else
return 0;
}
int main() {
int t, x, y, n;
double v, sum = 0;
scanf("%d", &t);
while (t--) {
sum = 0;
scanf("%lf %d", &v, &n);
for (int i = 0; i < n; i++) {
scanf("%d %d", &x, &y);
sum += F(x, y, v);
}
if (1.0 * sum / n >= 0.6)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
L. 签到
如果这个都不会就remake吧。。。
#include<stdio.h>
int main(){
puts("A Cute Meizi!");
return 0;
}