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)

posted @ 2021-03-06 22:39  流白李  阅读(150)  评论(0编辑  收藏  举报