2024年第15届蓝桥杯c++B组国赛个人题解(持续更新)

A 合法密码(暴力)

在这里插入图片描述

答案

400
kfdhtshmrw4nxg#f44ehlbn33ccto#mwfn2waebry#3qd1ubwyhcyuavuajb#vyecsycuzsmwp31ipzah#catatja3kagbcss2th

对着pdf看了好久qwq
点个赞吧xdm

代码

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

bool isValid(const string& s) {
    int num = 0, sym = 0;
    for (char c : s) {
        if (isdigit(c)) num += 1;
        if (!isalnum(c)) sym += 1;
    }
    return num > 0 && sym > 0;
}

int main() {
    string s = "kfdhtshmrw4nxg#f44ehlbn33ccto#mwfn2waebry#3qd1ubwyhcyuavuajb#vyecsycuzsmwp31ipzah#catatja3kagbcss2th";
    int n = s.size();
    int res = 0;
    for (int len = 8; len <= 16; ++len) {
        for (int i = 0; i <= n - len; ++i) {
            string sub = s.substr(i, len);
            if (isValid(sub)) {
                res += 1;
            }
        }
    }
    cout << res << endl;
    return 0;
}

B 选数概率(暴力)

在这里插入图片描述

这里先把比值模拟出来再暴力就可以了
因为底都是相同的;

a × b = 2585 a \times b = 2585 a×b=2585
b × c = 2632 b \times c = 2632 b×c=2632
a × c = 1540 a \times c = 1540 a×c=1540

我们通过两式相除法来简化问题并求出 (a)、(b)、(c) 的比值。

我们有以下三个方程:

a × b = 2585 a \times b = 2585 a×b=2585

b × c = 2632 b \times c = 2632 b×c=2632

a × c = 1540 a \times c = 1540 a×c=1540

通过相除来求比值:

首先,将第一个方程和第三个方程相除:

a × b a × c = 2585 1540 \frac{a \times b}{a \times c} = \frac{2585}{1540} a×ca×b=15402585

可以简化为:

b c = 2585 1540 \frac{b}{c} = \frac{2585}{1540} cb=15402585

接下来,将第二个方程和第三个方程相除:

b × c a × c = 2632 1540 \frac{b \times c}{a \times c} = \frac{2632}{1540} a×cb×c=15402632

可以简化为:

b a = 2632 1540 \frac{b}{a} = \frac{2632}{1540} ab=15402632

最后,将第一个方程和第二个方程相除:

a × b b × c = 2585 2632 \frac{a \times b}{b \times c} = \frac{2585}{2632} b×ca×b=26322585

可以简化为:

a c = 2585 2632 \frac{a}{c} = \frac{2585}{2632} ca=26322585

现在,我们得到三个比值:

b c = 2585 1540 , b a = 2632 1540 , a c = 2585 2632 \frac{b}{c} = \frac{2585}{1540}, \quad \frac{b}{a} = \frac{2632}{1540}, \quad \frac{a}{c} = \frac{2585}{2632} cb=15402585,ab=15402632,ca=26322585

我们可以将它们转换成 (a)、(b)、(c) 的比值:

首先,计算 (b : c):

b : c = 2585 1540 b : c = \frac{2585}{1540} b:c=15402585

然后,计算 (b : a):

b : a = 2632 1540 b : a = \frac{2632}{1540} b:a=15402632

最后,计算 (a : c):

a : c = 2585 2632 a : c = \frac{2585}{2632} a:c=26322585

选择 (a_1) 为 1,那么:

a : b : c = 1 : 2632 1540 : 2632 2585 a : b : c = 1 : \frac{2632}{1540} : \frac{2632}{2585} a:b:c=1:15402632:25852632

将其化简:

a : b : c = 3980900 : 6803720 : 4053280 a : b : c = 3980900 : 6803720 : 4053280 a:b:c=3980900:6803720:4053280

gcd( 3980900,gcd(4053280,6803720) ) 

化简 可知 式子同除72380

最后,得到 (a : b : c) 的比值为:

a : b : c = 55 : 94 : 56 a : b : c = 55 : 94 : 56 a:b:c=55:94:56

已经是互质的,所以答案就是这个。

55,94,56

C 蚂蚁开会

在这里插入图片描述

在这里插入图片描述

输入一

4
0 0 4 4
0 4 4 0
2 0 0 4
2 1 2 3

输出

2

通过端点求出直线
这里使用gcd

通过模拟一下可以发现 0 0 到 4 4 的 x,y 距离就是 4 4
gcd(4, 4) = 4
然后每次跳的偏移量就是 4 / 4 = 1,4 / 4 = 1
也就是0 0 4 4 这条直线可以穿过 0 0 ,1 1 ,2 2,3 3 ,4 4 这几个点。

每次只枚举整数点
把经过的点存入map
最后遍历map得出答案

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
const int N = 510, M = 10010;
struct line{
    PII p1, p2;
}s[N];
int n, num;
map<PII, int> cnt;
PII points[N * M];

void get_points(line l)
{
    int x1 = l.p1.first, y1 = l.p1.second;
    int x2 = l.p2.first, y2 = l.p2.second;
    int dx = x2 - x1, dy = y2 - y1;
    int d = __gcd(abs(dx), abs(dy));
    dx /= d, dy /= d;
    for (int i = 0;; ++i)
    {
        int x = x1 + i * dx, y = y1 + i * dy;
        points[++num] = {x, y};
        if (x == x2 && y == y2) break;
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> s[i].p1.first >> s[i].p1.second;
        cin >> s[i].p2.first >> s[i].p2.second;
    }
    for (int i = 1; i <= n; ++i)
    {
        get_points(s[i]);
    }

    int ans = 0;
    for (int i = 1; i <= num; ++i)
    {
        cnt[points[i]]++;
        if (cnt[points[i]] == 2)
            ans++;
    }

    cout << ans << endl;

    return 0;
}

考场上当时是暴力模拟的

D 立定跳远

在这里插入图片描述

在这里插入图片描述

应该是二分,但是稍微有点复杂

#include "bits/stdc++.h"

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    auto check = [&](int x) {
        int need = 0;
        for (int i = 1; i <= n; i++) {
            need += max(0, (a[i] - a[i - 1] + x - 1) / x - 1);
        }
        return need <= m + 1;
    };

    int l = 1, r = 1E8, ans = 0;
    while (l <= r) {
        int m0 = (l + r) >> 1;
        if (check(m0)) {
            r = m0 - 1;
            ans = m0;
        } else {
            l = m0 + 1;
        }
    }
    cout << ans << '\n';

    return 0;
}

借鉴的知乎大佬的
在这里插入图片描述

E 最小字符串 (暴力)

在这里插入图片描述

第一组

4 3
abbc
cba

输出

aabbbcc

第二组

7 3
lanqiao
bei

输出

beilanqiao

这题直接贪心
签到题

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 100010;

int main()
{
   ios :: sync_with_stdio(false);
   cin.tie(nullptr);

   int n, m;
   cin >> n >> m;
   string s, p;
   cin >> s >> p;
   sort(p.begin(), p.end());

   int i = 0, j = 0;
   while(i < n && j < m)
   {
       if(s[i] > p[j])
       {
           cout << p[j++];
       }
       else if(s[i] == p[j])
       {
           cout << s[i++];
           cout << p[j++];
       }
       else
       {
           cout << s[i++];
       }
   }

   while(i < n)
   {
       cout << s[i++];
   }

   while(j < m)
   {
       cout << p[j++];
   }

   return 0;
}

F 数位翻转

在这里插入图片描述

输入一

5 3
11 12 13 14 15

输出

67

输入二

6 2
23 8 11 19 16 35

输出

134

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/50bf10eba01e4d00879d515426ee582d.pn

这题感觉正解就是暴力
我感觉也不会TLE
首先模拟翻转之后会增加的ai
然后打上标记
记录翻转后的值
最后做一个区间合并再排序就行了

构造的特例如下

5 1
11 11 15 11 11

处理后的数组为

13 13 15 13 13

这里就是把整个数组整体处理一遍
所以打标记的时候需要将相等的也打上!!!!

最后做一个区间合并就行了
细节比较多,不好拿分。

	#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1010;
int n, m;
LL a[N], w[N];
bool st[N];

bool cmp(int a, int b)
{
    return a > b;
}   


LL get_val(LL x)
{
    LL res = 0;
    while (x)
    {
        res = (res << 1) | (x & 1);
        x >>= 1;
    }
    return res;
}





int main()
{
    cin >> n >> m;
    LL sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        sum += a[i];
    }
    for (int i = 1; i <= n; ++i) w[i] = get_val(a[i]);
    // for(int i = 1; i <= n; ++i) cout << w[i] << " ";

    for(int i = 1;i <= n;i ++ )
    {
        if(w[i] >= a[i]) st[i] = true;
    }
    int res = 0;

    vector<int> ans;

    for(int i = 1;i <= n;i ++)
    {
        if(st[i] && !st[i + 1])
        {
            res += w[i] - a[i];
            ans.push_back(res);
            res = 0;        
        }
        else if(st[i] && st[i + 1])
        {
            res += w[i] - a[i];
        }
        

    }
    sort(ans.begin(), ans.end(),cmp);
    
    for(int i = 0;i < m && i < ans.size();i ++)
    {
        sum += ans[i];
    
    }

    cout << sum << endl; 


    

    
   
    return 0;
}

但是这其实是一种贪心的策略,不保证一定是对的
下面的dp写法应该才是真正的正解

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
vector<int> in;

int fan(int x)
{
	int ans=0;
	for(;x;x>>=1)
	{
		ans=((ans<<1)|(x&1));
	}
	return ans;
}
void read()
{
	cin>>n>>m;
	in=vector<int>(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>in[i];
	}
}
int solve()
{
	const int inf=1e16;
	vector<vector<int>> dp(2,vector<int>(2*m+1,-inf));
	int now=1,old=0;
	dp[now][0]=0;
	for(int w=1;w<=n;w++)
	{
		swap(now,old);
		dp[now]=vector<int>(2*m+1,-inf);
		for(int sta=0;sta<=2*m;sta++)
		{
			dp[now][sta]=max(dp[old][sta],sta?dp[old][sta-1]:-inf)+((sta&1)?fan(in[w]):in[w]);
		}
	}
	int ans=0;
	for(int sta=0;sta<=2*m;sta++)
	{
		ans=max(ans,dp[now][sta]);
	}
	return ans;
}
signed main()
{
	read();
	cout<<solve();
}

亲亲们点个赞呗

G 数星星

在这里插入图片描述

输入一

6
1 2
1 3
2 4
2 5
3 6
3 4

输出

6

g)
统计每个点的度数,然后组合数一下。

#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;

typedef long long LL;
const int N = 1e5 + 10;
int n, deg[N];
int l, r;
LL fac[N], inv[N], ans[N];

LL qmi(LL a, LL b, LL p)
{
    LL res = 1;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}

void init()
{
    fac[0] = inv[0] = 1;
    for (int i = 1; i <= n; ++i)
    {
        fac[i] = fac[i - 1] * i % mod;
    }
    for (int i = 1; i <= n; ++i)
    {
        inv[i] = qmi(fac[i], mod - 2, mod);
    }
}

LL C(int n, int m)
{
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int main()
{
    cin >> n;
    init();
    for (int i = 1; i < n; ++i)
    {
        int a, b;
        cin >> a >> b;
        ++deg[a], ++deg[b];
    }
    cin >> l >> r;
    ans[1] = n, ans[2] = n - 1;
    for (int i = 1; i <= n; ++i)
    {
        if (deg[i] >= 2)
        {
            for (int j = 3; j <= deg[i] + 1; ++j)
            {
                ans[j] = (ans[j] + C(deg[i], j - 1)) % mod;
            }
        }
    }

    LL sum = 0;
    for (int i = l; i <= r; ++i)
        sum = (sum + ans[i]) % mod;
    cout << sum << endl;
    return 0;
}

H 套手镯

在这里插入图片描述

8 12 9
18 22 1
3 17 2
21 28 1
7 18 2
10 2 2
4 24 2
19 13 1
14 15 1

输出

3

在这里插入图片描述
在这里插入图片描述

#include "bits/stdc++.h"

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, w, h;
    cin >> n >> w >> h;

    vector<int> x(n), y(n), r(n);
    for (int i = 0; i < n; i++) {
        cin >> x[i] >> y[i] >> r[i];
    }

    int ans = 0;

    auto work = [&](int x0, int y0, int h, int w) {
        int x1 = x0 + h, y1 = y0 + w;
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (x[i] - r[i] >= x0 && x[i] + r[i] <= x1) {
                if (y[i] - r[i] >= y0 && y[i] + r[i] <= y1) {
                    res++;
                }
            }
        }
        ans = max(ans, res);	
    };

    for (int i = 0; i < n; i++) {
        work(x[i] - r[i], y[i] - r[i], h, w);
        work(x[i] - r[i], y[i] - r[i], w, h);

        work(x[i] + r[i] - h, y[i] + r[i] - w, h, w);
        work(x[i] + r[i] - w, y[i] + r[i] - h, w, h);

        work(x[i] - r[i], y[i] + r[i] - h, w, h);
        work(x[i] - r[i], y[i] + r[i] - w, h, w);

        work(x[i] + r[i] - h, y[i] - r[i], h, w);
        work(x[i] + r[i] - w, y[i] - r[i], w, h);
    }

    cout << ans << '\n';

    return 0;
}

这个也是借鉴的
在这里插入图片描述

I 跳石头

在这里插入图片描述

输入

5
4 3 5 2 1

输出

4

在这里插入图片描述

这题是暴力,算了一下可能会超时

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1000010;

int a[N];
int n;

void dfs(int u,set<int> &s)
{
    if(u > n)  return;
    if( u * 2 <= n)
    {
        s.insert(a[u * 2]);
        dfs(u * 2,s);
    }
    if(u + a[u] <= n)
    {
        s.insert(a[u + a[u]]);
        dfs(u + a[u],s);
    }
    return;
}


int main()
{
	ios :: sync_with_stdio(false);
    cin.tie(nullptr); 
    cin >> n;
    
    for(int i = 1;i <= n;i ++)
    {
        cin >> a[i];   
    }

    int maxv = -1;


    for(int i = 1;i <= n;i ++)
    {
        set<int> s;
        s.insert(a[i]);
        dfs(i,s);
        maxv = max(maxv,(int)s.size());
    }
    
    cout << maxv << endl;
	
	
	return 0;
}

还有一种写法是拓扑排序

#include <bits/stdc++.h>
using namespace std;

const int N = 40010;
bitset<N> st[N];
int n, c[N], deg[N];
vector<int> e[N];

void bfs()
{
    queue<int> q;
    for (int i = 1; i <= n; ++i)
        if (!deg[i]) q.push(i);
    while (q.size())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < e[u].size(); ++i)
        {
            int v = e[u][i];
            st[v] |= st[u];
            if (--deg[v] == 0) q.push(v);
        }
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> c[i];
        st[i][c[i]] = 1;
        if (i * 2 <= n)
        {
            ++deg[i];
            e[i * 2].push_back(i);
        }
        if (i + c[i] <= n)
        {
            ++deg[i];
            e[i + c[i]].push_back(i);
        }
    }
    bfs();
    int ans = 0;
    for (int i = 1; i <= n; ++i)
    {
        int m = st[i].count();
        ans = max(ans, m);
    }
    cout << ans << endl;
    return 0;
}

J 最长回文前后缀

在这里插入图片描述

输入

abcdebijbba

输出

3

在这里插入图片描述
在这里插入图片描述

听说是kmp
但是暴力也不是不能写对吧😋

总结

由于目前还没有测试网站,所以代码并不保证一定能ac只是提供一个思路给大家,大家喜欢的可以点点关注

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值