2025牛客寒假算法基础集训营4部分题解

1 前言:

这次感觉并不算难,题目基本思考时间很短,但是只做出来了6题。原因大概是过年过迷糊了,实现上出了很多小错误加上比赛过了一小时才开始。

2 题解

K Tokitsukaze and Shawarma

签到题,三种时长去max即可。

 void solve()
{
    int x,y,z,a,b,c;
    cin>>x>>y>>z>>a>>b>>c;
    cout << max({x * a, y * b, z * c}) << endl;
    
} 

I Tokitsukaze and Pajama Party

题目要求u和uwawauwa之间至少有一个字符,可以将所有uwawauwa所在的下标进行标记,再从右往左做一个前缀和。之后遍历字符串,对于每一个u所在的下标index,将前缀和下标为index+2的值累加进答案即可。

 void solve()
{
    int arr[100005];
int pre[100005];
char str[100005];
string s = "uwawauwa";
void init()
{
    memset(pre, 0, sizeof(pre));
    memset(arr, 0, sizeof(arr));
}
void solve()
{
    init();
    int n;
    cin >> n;

    for (int i = 1; i <= n; i++)
    {
        cin >> str[i];
    }
    for (int i = 1; i <= n; i++)
    {
        int ok = 1;
        for (int j = 0; j < 8; j++)
        {
            if (i + j > n)
            {
                ok = 0;
                break;
            }
            if (s[j] != str[i + j])
            {
                ok = 0;
                break;
            }
        }
        if (ok == 1)
        {
            arr[i] = 1;
        }
    }

    for (int i = n; i >= 1; i--)
    {
        pre[i] = pre[i + 1] + arr[i];
    }

    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        if (str[i] == 'u')
        {
            ans += pre[i + 2];
        }
    }
    cout << ans << endl;
}
    
} 

E Tokitsukaze and Dragon's Breath

可以注意到龙之吐息的范围是一条正斜线与一条反斜线相交,并且任意一个点都可以释放龙之吐息。这意味着地图上每一个点都可以作为一条正斜线与一条反斜线相交。那么我们遍历正斜线与反斜线,并将每条斜线的怪物数量和加到斜线上的方格中,由于交点会重复计算,最终消灭的怪物数量还要减去交点方格的怪物数量。
遍历正斜线我用矩形左边与上边的方格为起点,令x++,y++,直到出界,反斜线同理。

 void solve()
{
    bool check(int x, int y)
{
    if (x > n || x < 1 || y > m || y < 1)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
void init()
{
}
void solve()
{
    // init();
    tot1 = 0;
    tot2 = 0;
    cin >> n >> m;
    vector<int> line1(n + m + 5, 0);
    vector<int> line2(n + m + 5, 0);
    vector<vector<int>> val(n + 2, vector<int>(m + 2, 0));
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> crood[i][j];
        }
    }

    for (int i = 1; i <= m; i++)
    {
        int x1 = 1, y1 = i, x2 = 1, y2 = i;
        tot1++;
        tot2++;

        while (check(x1, y1))
        {
            line1[tot1] += crood[x1][y1];
            x1++;
            y1++;
        }
        while (check(x2, y2))
        {
            line2[tot2] += crood[x2][y2];
            x2++;
            y2--;
        }
        x1 = 1, y1 = i, x2 = 1, y2 = i;
        while (check(x1, y1))
        {
            val[x1][y1] += line1[tot1];

            x1++;
            y1++;
        }
        while (check(x2, y2))
        {
            val[x2][y2] += line2[tot2];

            x2++;
            y2--;
        }
    }
    for (int i = 2; i <= n; i++)
    {
        int x1 = i, y1 = 1, x2 = i, y2 = m;
        tot1++;
        tot2++;
        while (check(x1, y1))
        {
            line1[tot1] += crood[x1][y1];
            x1++;
            y1++;
        }
        while (check(x2, y2))
        {
            line2[tot2] += crood[x2][y2];
            x2++;
            y2--;
        }
        x1 = i, y1 = 1, x2 = i, y2 = m;
        while (check(x1, y1))
        {
            val[x1][y1] += line1[tot1];
            x1++;
            y1++;
        }
        while (check(x2, y2))
        {
            val[x2][y2] += line2[tot2];

            x2++;
            y2--;
        }
    }
    int maxn = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            maxn = max(maxn, val[i][j] - crood[i][j]);
        }
    }
    cout << maxn << endl;
}
    
} 

C/B Tokitsukaze and Balance String (hard)

这题我直接做了hard ver同时交了两道题,所以直接放一起了。
首先可以注意到,连续的1和连续的0都可以看作一个,01001111110没有区别,简化后我们发现一共只有四种情况:

  1. 0开头1结尾
  2. 0开头0结尾
  3. 1开头0结尾
  4. 1开头1结尾
    其中头尾相同时,这个字符串的就是平衡的(保证每个0左右两边都有1或者每个1左右两边都有0)。所以头尾相同时字符串 valn2,可以更改除了头尾外的任意字符,头尾依旧相同,不同时为2,原因同理。
    这样之后其实我们只有关注 ? 的数量与头尾是否存在 ? ,当头尾都为 ? 时存在两种头尾相同与两种头尾不同的情况,去掉头尾后共有p-2个 ? 所以答案为 (n2)2(p2)2+22(p2)2 其余的分类情况读者自行思考。
void solve()
{
    // init();

    int cnt = 0;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> arr[i];
        if (arr[i] == '?')
        {
            cnt++;
        }
    }
    if (n == 1)
    {
        if(arr[1]=='?')
        {
            cout << '2' << endl;
        }
        else
        {
            cout<<'1'<<endl;
        }
        return;
    }
    int pow1 = 0, pow2 = 0, pow3 = 0, tmp = 1;
    for (int i = 0; i <= cnt; i++)
    {
        if (i == cnt - 2)
        {
            pow1 = tmp;
        }
        if (i == cnt - 1)
        {
            pow2 = tmp;
        }
        if (i == cnt)
        {
            pow3 = tmp;
        }
        tmp *= 2;
        tmp %= mod;
    }
    int ans = 0;
    if (arr[1] == '?' && arr[n] == '?')
    {
        ans += n * pow1 * 2;
        ans %= mod;
    }
    else if (arr[1] == '?' && arr[n] != '?')
    {
        ans += n * (pow2);
        ans %= mod;
    }
    else if (arr[1] != '?' && arr[n] == '?')
    {
        ans += n * (pow2);
        ans %= mod;
    }
    else if (arr[1] == arr[n])
    {
        ans += (n - 2) * pow3;
        ans %= mod;
    }
    else
    {
        ans += 2 * pow3;
        ans %= mod;
    }
    cout << ans % mod << endl;
}

D | Tokitsukaze and Concatenate‌ Palindrome

这题的字符顺序可以任意调换,只需要贪心地匹配字符即可。具体贪心方法如下:
先存入长的字符串的字母数量,再匹配短的字符串,匹配上相同的字符则存入的字母数量要减一,无法匹配的字符数量记为cnt1,这里记为两边的未匹配字母。长的字符串剩下的字母与其匹配后剩下的字母记为中间的字母,中间的字母数量和为奇数的字母记为中间的未匹配字母将其数量记为cnt2,中间未匹配的字母可以移到两边变为对应需要的字母。由于两边的未匹配字母由短的字符串产生,无法移动到中间,所以答案为 max(cnt2cnt1,cnt1)

string arra, arrb;
map<char, int> mp1;
int n, m;

void init()
{
    mp1 = map<char, int>();
}
void solve()
{
    init();
    int ans = 0, cnt = 0;
    cin >> n >> m;
    cin >> arra >> arrb;
    arra = '0' + arra;
    arrb = '0' + arrb;
    if (n < m)
    {
        swap(arra, arrb);
        swap(n, m);
    }
    for (int i = 1; i <= n; i++)
    {
        mp1[arra[i]]++;
    }
    for (int i = 1; i <= m; i++)
    {
        if (mp1[arrb[i]] == 0)
        {
            ans++;
        }
        else
        {
            mp1[arrb[i]]--;
        }
    }
    for (auto it : mp1)
    {
        if (it.second % 2 == 1)
        {
            cnt++;
        }
    }
    if (cnt >= ans)
    {
        ans += (cnt - ans) / 2;
    }

    cout << ans << endl;
}

3 总结

过个年手有点生,训练强度有点低了,希望队伍的leader能发挥威严给我们上上强度

posted @   青一凡  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示