2024第一场新生赛个人题解

今年的各位也超强的啊

Posted by BingYu2016 on August 31, 2024

注:题解给出顺序按(自认为的)题目难度顺序排序

B:ICPC与小鹿的差旅费用规划

最基础的A+B问题,注意题目给出的票价是单程票价,应计算两次,同时注意题目中给出的a和b的最大值均为 $2 \cdot 10^{15}$ ,应使用long long类型存储

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<bits/stdc++.h>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        long long a,b;
        cin>>a>>b;
        cout<<a*2+b<<endl;
    }
    return 0;
}

D:百度之星与小鹿的铁牌

根据题干,可知除格子1,2以外,其他格子的可能路线均为其左侧两格子可能路线之和。再对样例稍加观察后,不难发现本题其实就是斐波那契数列的换皮版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<bits/stdc++.h>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int a[n+1];
        a[0]=0;a[1]=1;
        for(int i=2;i<=n;i++) a[i]=a[i-1]+a[i-2];
        cout<< a[n] <<endl;
    }
    return 0;
}

E:蓝桥杯与鹿与小面包

因为每次必须删除连续的 $k$ 个数,数组中的数某个一项如果能够在最终被保留,那么其左侧和右侧的项的数量都应恰好为 $k$ 的倍数,又因题目限定 $N$ $mod$ $k$ $=$ $1$ ,所以该条件前半段满足时后半段自然满足,因此,我们只需要遍历所有左侧项数等于k的倍数的项,并取最大值即可

1
2
3
4
5
6
7
8
9
10
11
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n,k;
    cin>>n>>k;
    int a[n],ans=0;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i+=k) ans=max(ans,a[i]);
    cout<<ans;
}

A:网络竞赛平台与小鹿与正在检验你是否是真人请稍后

首先,统计每个给出的数中每一个数字出现了多少次,将其存储于数组中,随后每次从其中取出一个最小的数字,直到数组被取完即可。需要注意的是,对第一次取数不能取0,此处应给出特判。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        int num[15]={0};
        string s;
        cin>>s;
        for(int i=0;i<s.size();i++)num[s[i]-'0']++;

        for(int i=1;i<=9;i++){
            if(num[i]){
                cout<<i;
                num[i]--;
                break;
            }
        }

        for(int j=1;j<s.size();j++){
            for(int i=0;i<=9;i++){
                if(num[i]){
                    cout<<i;
                    num[i]--;
                    break;
                }
            }
        }

        cout<<endl;
    }
}

G:天梯赛与小鹿与字符串维护

正如标题所说,这题的核心就是字符串维护,因为N较小,直接使用暴力方法即可通过本题

如果使用C的char数组解题的话,在处理这些操作时恐怕会麻烦颇多,也相对容易写出很多奇怪的bug,如果这题写不出来的话就去学学string的用法吧,绝对会很有用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<bits/stdc++.h>
using namespace std;

int a[26];

long long getsum(string s){
    long long res=0;
    for(int i=0;i<s.size();i++) res+=a[s[i]-'a'];
    return res;
}

int main(){
    int n;
    cin>>n;
    string s;
    cin>>s;

    for(int i=0;i<26;i++) cin>>a[i];

    int q;
    cin>>q;
    while(q--){
        int orp;
        cin>>orp;

        if(orp==1){
            string ss;
            cin>>ss;
            s=s+ss;
        }

        if(orp==2){
            cout<<getsum(s)<<endl;
        }

        if(orp==3){
            int l,r;
            cin>>l>>r;
            s.erase(l-1,r-l+1);
        }
    }
    return 0;
}

F:睿抗与小鹿的贪心消消乐

此题有两个难点,如何判断三点相邻和如何处理万能符号.

在经过对出题人的拷打过后,如何判断三个点相邻的方法已经作为解释写明在题干上了,先判断是否存在横坐标或纵坐标均相等,再判断另一者是否公差为1,考虑到三个点均不相同,判断其中最大者减最小者是否为2即可

对于.这一万能符号,我们可以考虑在判断是否能消除时,使用三个变量存储RGB各自的数量,.同时视作R、G、B,之后判断是否有其一等于3即可

本题如果能学会C++中STL容器里的string的一些基础用法的话,写起来想必会舒服非常多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;


int main(){
    int n;
    cin>>n;

    string s[n+1];
    for(int i=1;i<=n;i++){
        cin>>s[i];
        s[i]='x'+s[i]; //这个x是个占位符,保证原字符串从下标1处开始
    }

    int q;
    cin>>q;

    while(q--){
        int opr;
        cin>>opr;

        if(opr==1){
            int x[4],y[4];
            cin>>x[1]>>y[1]>>x[2]>>y[2]>>x[3]>>y[3];
            int r=0,g=0,b=0,lk=0;
            //lk用于判断三个坐标是否相邻且成行

            if(x[1]==x[2]&&x[1]==x[3]){
                if( max({y[1],y[2],y[3]}) - min({y[1],y[2],y[3]}) ==2)
                lk=1;
            }
            if(y[1]==y[2]&&y[1]==y[3]){
                if( max({x[1],x[2],x[3]}) - min({x[1],x[2],x[3]}) ==2)
                lk=1;
            }

            if(!lk){
                cout<<"NO"<<endl;
                continue;
            }

            for(int i=1;i<4;i++){
                if(s[x[i]][y[i]]=='R')
                r++;
                if(s[x[i]][y[i]]=='G')
                g++;
                if(s[x[i]][y[i]]=='B')
                b++;
                if(s[x[i]][y[i]]=='.')
                r++,g++,b++;
            }

            if(r==3||g==3||b==3) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
        else{
            int x,y;
            string z;
            cin>>x>>y>>z;
            //此处用字符串存储修改是为了避免读入多余的空格与换行
            s[x][y]=z[0];
        }
    }
}

C:CCPC与饭后消食的小鹿

如果用暴力做法的话,每一步在上一步的基础上延申出两种可能,那么最终的可能性就是 $2^n$ 个,显然无法通过此题。但我们注意到其可能产生的 状态 ,即小鹿在某次动作开始时所站的位置,只有最多x种,因而我们可以尝试对每一次动作枚举其发生时可能的状态,这样复杂度就能够被控制在O( $n \cdot x$ )的级别了

具体而言,我们可以建立一个二维数组 $dp$ ,我们将 $dp[i][j]$ 定义为在第 $i$ 次操作后,能否到达第 $j$ 个格子。最初,我们将 $dp[0][0]$ 设为 $1$ (即未进行任何操作时,能够到达第0个格子),其余值设为 $0$ 。随后,对于第 $i$ 次操作,我们遍历上一次操作产生的 $dp[i-1]$ 数组,如果 $dp[i-1][j]$ 是 $1$ ,即上一次操作后能够到达第 $j$ 格,那么在本次操作中,第 $j+a_i$ 和 $j+b_i$ 这两个格子也是能够达到的(前提是这两个格子不大于 $x$ ),即 $dp[i][j+a_i],dp[i][j+b_i]$ 均也为 $1$ 。依照此方法遍历完所有 $n$ 次操作后,我们只需要检查 $dp[n][x]$ 是否为 $1$ 即可。

这种做法基于动态规划(DP)的思想,如果你自己悟出了此题的解法,大概有日后成为队里DP手的潜力(?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<bits/stdc++.h>
using namespace std;

int main(){
    int dp[110][10010];
    int n,x;
    cin>>n>>x;
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;

    for(int i=1;i<=n;i++){
        int a,b;
        cin>>a>>b;

        for(int j=a;j<=x;j++){
            if(dp[i-1][j-a]){
                dp[i][j]=1;
            }
        }

        for(int j=b;j<=x;j++){
            if(dp[i-1][j-b]){
                dp[i][j]=1;
            }
        }
    }

    if(dp[n][x])cout<<"YES";
    else cout<<"NO";
    return 0;
}

DLC:热身赛题解

复刻早年入队赛经典了属于是

1
BBBBBBBBBBBB