2025牛客寒假算法基础集训营2题解(ABCDFGHJK)

比赛链接:2025牛客寒假算法基础集训营2

 

A-一起奏响历史之音!

思路:模拟即可。时间复杂度 O(1) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int main()
{
    IOS;
    bool flag=0;
    rep(i,1,7)
    {
        int a;
        cin >> a;
        if(a==4||a==7)
            flag=1;
    }
    if(flag)
        cout << "NO" ;
    else 
        cout << "YES";
    return 0;
}

 

B-能去你家蹭口饭吃吗

思路:排序数组然后遍历找到所求值即可。时间复杂度 O(n log n) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int n;
double a[500005];

int main()
{
    IOS;
    cin >> n;
    rep(i,1,n)
        cin >> a[i]; 
    sort(a+1,a+1+n);
    if(n%2==0)
        cout << a[n/2+1]-1;
    else
        cout << a[(n+1)/2]-1;
    return 0;
}

 

C-字符串外串

思路:根据 D 题的思路,为了方便起见,我们采取倒过来遍历字符串的操作,字符串的开头就是最靠左的 a[i] 之前 a[j] 的字符所在处,我们以 a[i] 和 a[j] 来把字符串划分成两段,我们设 a[i] 和 a[j] 都为 ‘a’ ,然后得到 {a....}{a......} 如果我们设第二段长度为 m ,则第一段长度为 n - m ,显然发现 n 必须大于 m ,同时,为了确保不会存在更优的选择,两段的 a 后面都不能存在相同的字符,于是必须有 n - m <= 26 ,因为这是不存在相同字母的必要条件。由以上分析得到,除了两个 a 以外其他字母都不重要,我们最好是按顺序循环将字母填入长为 n 的字符串(第一段按顺序填 n - m 个字母,第二段按顺序填 m 个字母,可以通过取模轻松做到这点)。时间复杂度 O(n)  可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
        int n,m;
        cin >> n >> m;
        if(m==n||n-m>26)
            cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            rep(i,1,n)
                cout << (char)('a' + (i-1) % (n - m));
            cout << endl;
        }
    }
    return 0;
}

 

D-字符串里串

思路:我们发现,正着遍历字符串时,如果 a[i] 之后还存在 a[j] 与 a[i] 相同,那么我们可以就拆出 [1, i - 1] 与 [j, j] 这两个子串组成符合题意的相等的子串和子序列。由于要求长度的最大值,贪心地思考,我们找到这样的 i 的最大值即可。注意,由于“找 a[i] 后的相同的 a[j] ”该操作具有方向性,所以还需将字符串反着遍历操作一遍,最后取两种操作后的最大值。时间复杂度 O(n) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

unordered_map<char, int> mp1, mp2;

int main()
{
    IOS;
    int n;
    string s;
    cin >> n >> s;
    s = '0' + s;
    rep(i, 1, n)
    {
        mp1[s[i]]++;
        mp2[s[i]]++;
    }
    int maxi = 0;
    rep(i, 1, n)
    {
        mp1[s[i]]--;
        if (mp1[s[i]] != 0)
            maxi = max(maxi, i);
    }
    int mini = n + 1;
    per(i, n, 1)
    {
        mp2[s[i]]--;
        if (mp2[s[i]] != 0)
            mini = min(mini, i);
    }
    if (maxi == 0 && mini == n + 1)//都没找到
        cout << 0;
    else if (maxi == 1 && mini != n)
        cout << n-mini+1;
    else if (mini == n && maxi != 1)
        cout << maxi;
    else if (maxi == 1 && mini == n)
        cout << 0;
    else
        cout << max(maxi,n-mini+1);
    return 0;
}

 

F-一起找神秘的数!

思路:按位分解 x 和 y 为 xi 和 yi ,可以发现 xi​ + yi​ == (xi​ OR yi​) + (xi​ AND yi​),于是x​ + y ​== (x​ OR y​)+(x​ AND y​),从而 x​ + y ​== x + y + (x XOR y),显然有 x XOR y == 0 可以推出 x == y ,那么 x 和 y 的组数就等于区间长度。时间复杂度 O(1) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int t;

int main()
{
    IOS;
    cin >> t;
    while(t--)
    {
        LL l,r;
        cin >> l >> r;
        cout << r-l+1 << endl;
    }
    return 0;
}

 

G-一起铸最好的剑! 

思路:如果 m == 1 那么无论温度提高多少次都是 1 ,所以提高 1 次就行,剩下的模拟即可。时间复杂度 O(log n) 可以通过此题。 

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int t;

int main()
{
    IOS;
    cin >> t;
    while(t--)
    {
        int n,m;
        cin >> n >> m;
        if(m==1)
        {
            cout << 1 << endl;
            continue;
        }
        int i=1;
        LL pro=m;
        int minn=INT_MAX;
        int ans=0;
        while(1)
        {
            if(minn>abs(n-pro))
            {
                minn=abs(n-pro);
                ans=i;
            }
            if(pro>n)
                break;
            pro*=m;
            i++;
        }
        cout << ans << endl;
    }
    return 0;
}

 

H-一起画很大的圆!

思路:设有线段AC和B,根据正弦定理贪心地思考,我们应该让 B 尽量靠近 AC ,让 AC 的长度尽量大,这样ABC确定的圆的半径才最大。时间复杂度 O(1) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        if(b-a>d-c)
        {
            cout << a << " " << d << endl;
            cout << a+1 << " " << d << endl;
            cout << b << " " << d-1 << endl;
        }
        else
        {
            cout << a << " " << c << endl;
            cout << a << " " << c+1 << endl;
            cout << a+1 << " " << d << endl;
        }
    }
    return 0;
}

 

J-数据时间?

思路:模拟即可。时间复杂度 O(n) 可以通过此题。 

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int tq,wx,ls;
unordered_map<string,bool>tqmp;
unordered_map<string,bool>wxmp;
unordered_map<string,bool>lsmp;

int main()
{
    int n,h,m;
    scanf("%d %d %d",&n,&h,&m);
    while(n--)
    {
        string ID;
        int Y,M,D,hh,mm,ss;
        cin >> ID;
        scanf("%d-%d-%d %d:%d:%d",&Y,&M,&D,&hh,&mm,&ss);
        if(Y==h&&M==m)
        {
            if(hh>=7&&hh<9||hh==9&&mm==0&&ss==0||hh>=18&&hh<20||hh==20&&mm==0&&ss==0)
            {
                if(tqmp[ID]==0)
                {
                    tq++;
                    tqmp[ID]=1;
                }
            }
            if(hh>=11&&hh<13||hh==13&&mm==0&&ss==0)
            {
                if(wxmp[ID]==0)
                {
                    wx++;
                    wxmp[ID]=1;
                }
            }
            if(hh>=22&&hh<=23||hh>=0&&hh<1||hh==1&&mm==0&&ss==0)
            {
                if(lsmp[ID]==0)
                {
                    ls++;
                    lsmp[ID]=1;
                }
            }
        }
    }
    printf("%d %d %d",tq,wx,ls);
    return 0;
}

 

K-可以分开吗?

思路:先对蓝色块用深搜将每个蓝色极大连通块编号,然后对灰色块深搜记录每个编号的联通块的周围的灰色块数量,最后取最小值即可。时间复杂度 O(n * m) 可以通过此题。

#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;

int n, m;
vector<string> a;
int b[505][505];
int num[250005];
bool vs1[505][505],vs0[505][505];
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

void dfs(int x, int y, int t)
{
    if (a[x][y] == '1')
    {
        b[x][y] = t;
    }
    rep(d, 0, 3)
    {
        int nx = x + dx[d], ny = y + dy[d];
        if (a[nx][ny] == '1' && vs1[nx][ny] == 0 && nx >= 1 && nx <= n && ny >= 1 && ny <= m)
        {
            vs1[nx][ny] = 1;
            dfs(nx, ny, t);
        }
    }
}

int main()
{
    IOS;
    cin >> n >> m;
    a.resize(n + 5);
    rep(i, 1, n)
    {
        string s;
        cin >> s;
        a[i] = '#' + s;
    }
    int t = 0;
    rep(i, 1, n)
    {
        rep(j, 1, m)
        {
            if (a[i][j] == '1' && vs1[i][j] == 0)
            {
                t++;
                vs1[i][j] = 1;
                dfs(i, j, t);
            }
        }
    }
    rep(i, 1, n)
    {
        rep(j, 1, m)
        {
            if (a[i][j] == '0' && vs0[i][j] == 0)
            {
                unordered_map<int,bool>vst(0);
                vs0[i][j] = 1;
                rep(d, 0, 3)
                {
                    int nx = i + dx[d], ny = j + dy[d];
                    if (a[nx][ny] == '1' && vst[b[nx][ny]]==0 && nx >= 1 && nx <= n && ny >= 1 && ny <= m)
                    {
                        vst[b[nx][ny]]=1;
                        num[b[nx][ny]]++;
                    }
                }
            }
        }
    }
    int minn = INT_MAX;
    rep(i, 1, t)
    {
        minn = min(minn, num[i]);
    }
    cout << minn;
    return 0;
}

 

 

### 关于2020年寒假算法基础集训营中的欧几里得算法2020年的寒假算法基础集训营中,确实存在涉及欧几里得算法的相关题目。具体来说,在第四场竞赛的第一题即为“A. 欧几里得”,该题目的核心在于利用扩展欧几里得定理来解决问题[^5]。 #### 扩展欧几里得算法简介 扩展欧几里得算法主要用于求解形如 ax + by = gcd(a, b) 的线性不定方程的一组特解(x,y),其中gcd表示最大公约数。此方法不仅能够计算两个整数的最大公因数,还能找到满足上述条件的具体系数x和y。 对于给定的数据范围较小的情况可以直接通过递归来实现;而对于较大数据则需考虑效率优化问题。下面给出了一段基于C++语言编写的用于解决此类问题的模板代码: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; // 定义全局变量存储结果 int x, y; void ex_gcd(int a, int b){ if(b == 0){ x = 1; y = 0; return ; } ex_gcd(b, a % b); int tmp = x; x = y; y = tmp - (a / b) * y; } ``` 这段程序实现了经典的扩展欧几里得算法逻辑,并且可以作为处理类似问题的基础工具函数调用。 #### 实际应用案例分析 回到原题本身,“A. 欧几里得”的解答思路就是先预处理斐波那契数列前若干项数值存入数组`a[]`内以便快速查询,之后针对每一次询问直接输出对应位置处两相邻元素之和即可得出最终答案。这实际上巧妙运用到了广为人知的裴蜀定理——任意一对互质正整数都可由它们自身的倍数组合而成,而这里正是借助了这一性质简化了解决方案的设计过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值