题解:牛客周赛 Round 72(A-D)(E只有代码)

先附上补题链接,没打的同学可以来补一下:

https://ac.nowcoder.com/acm/contest/98256


A 小红的01串(一)

题意

找到一个01串中相邻字符不同的对数

做法

从头到尾扫一遍,计算前后不一样的字符就可以了

#include <bits/stdc++.h>

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::string s;
    std::cin >> s;
    int ans = 0;
    for(int i = 0 ; i + 1 < s.size() ; i ++) {
        ans += (s[i] != s[i+1]);
    }

    std::cout << ans << "\n";
    
    return 0;
}

B 小红的01串(二)

题意

给你一个01串,输出相邻字符均不同的连续子串数量

做法

这题就是直接扫一遍,找到每一段 尽可能长的 相邻字符均不同 的字符串**(不要重复)**

写个双指针就好了

设共有 k k k 段字符串 , 每一个字符串 s i s_i si 的长度为 l i l_i li

对每一段字符串 s i s_i si ,里面任意一个连续子串都满足题意,因此需要计算出这个字符串里长度大于等于 2 2 2 的子串数量

可以理解为,对每一个字符可以看做开头,这个字符后面的任意字符看做结尾,那么这个字符串的符合题意子串数量为:

a n s = ∑ i = 1 k ( ( l i − 1 ) + ( l i − 2 ) ⋯ + 2 + 1 ) a n s = ∑ i = 1 k ( l i ∗ ( l i − 1 ) ÷ 2 ) ans = \sum_{i=1}^{k}{((l_i-1)+(l_i-2) \dots + 2 + 1)} \\ ans = \sum_{i=1}^{k}{(l_i * (l_i - 1) \div 2)} ans=i=1k((li1)+(li2)+2+1)ans=i=1k(li(li1)÷2)

#include <bits/stdc++.h>
#define int long long

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::string s;
    std::cin >> s;
    int ans = 0;
    int sum = 0;
    for(int i = 0 ; i < s.size() - 1; i ++) {
        if(s[i] != s[i+1]) sum ++;
        else if(sum) {
            ans += sum * (sum+1) / 2;
            sum = 0;
        }
    }

    if(sum) ans += sum * (sum+1) / 2;

    std::cout << ans << "\n";
    
    return 0;
}

C 小红的01串(三)

题意

给你 a a a 个’0’、 b b b 个’1’ 让你组成一个01串,该01串有恰好 k k k 对相邻的字符不同。

做法

这是一道构造题,要求构造一个字符串满足题意

构造方法:

要构造 k k k 个相邻不同,使 01 交替排列形成长度为 k + 1 k+1 k+1 字符串即可

如果无法构造以上字符串,就输出 − 1 -1 1

然后再把剩下的 0 和 1 塞到中间即可

注意特判 k = 0 或者 a = 0, b = 0

#include <bits/stdc++.h>
#define int long long

void solve() {
    int a,b,k;
    std::cin >> a >> b >> k;

    if(k == 0 && a > 0 && b > 0) {
        std::cout << -1 << "\n";
        return;
    }
    
    if(k == 0 && (a == 0 || b == 0)) {
        while(a--) std::cout << 0;
        while(b--) std::cout << 1;
        std::cout << "\n";
        return;
    }
    
    if(k != 0 && (a == 0 || b == 0)) {
        std::cout << -1 << "\n";
        return;
    }
    
    int mp[2] = {0,1};

    if(a > b) {
        std::swap(a,b);
        std::swap(mp[0],mp[1]);
    }

    if(a < (k+1)/2 || b < (k+2)/2) {
        std::cout << "-1" << "\n";
        return;
    }

    int last_a = a - (k+1)/2;
    int last_b = b - (k+2)/2;

    std::cout << mp[1];
    while(last_b --) std::cout << mp[1];
    std::cout << mp[0];
    while(last_a --) std::cout << mp[0];
    for(int i = 2 ; i <= k ; i ++) {
        std::cout << mp[(i+1)%2];
    }
    std::cout << "\n";
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int t = 1;
    std::cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}

D 小红的01串(四)

题意

小红拿到了一个01串,她初始站在第一个字符。小红可以进行以下移动方式:
1. 花费 x x x 能量,移动到当前位置右边、离当前位置最近的,和当前字符相同的字符;
2. 花费 y y y 能量,移动到当前位置右边、离当前位置最近的,和当前字符不同的字符。

小红想知道,她移动到最右端的最小花费是多少?

做法

dp 一下就好了

先从后往前扫一遍,找到每一个的下一个(一样的 和 不一样的)点 在哪里

然后再初始化dp数组为最大值,dp[0] = 0;

然后从前往后开始dp,更新每一个的下一个(一样的 和 不一样的)点的dp值(尽可能小)

然后输出最后一个的dp值即可

#include <bits/stdc++.h>
#define int long long
#define INF (int)1e18

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int n,x,y;
    std::string s;

    std::cin >> n >> x >> y >> s;

    std::vector<int> dp(n,INF);
    std::vector<std::vector<int> > next(n,std::vector<int>(2,-1));

    int two[2] = {INF,INF};

    for(int i = n-1 ; i >= 0 ; i --) {
        next[i][0] = (two[s[i] - '0'] == INF ? -1 : two[s[i] - '0']);
        next[i][1] = (two[1 - (s[i] - '0')] == INF ? -1 : two[1 - (s[i] - '0')]);

        two[s[i] - '0'] = i;
    }

    dp[0] = 0;
    for(int i = 0 ; i < n ; i ++) {
        if(next[i][0] != -1) {
            dp[next[i][0]] = std::min(dp[next[i][0]] , dp[i] + x);
        }
        if(next[i][1] != -1) {
            dp[next[i][1]] = std::min(dp[next[i][1]] , dp[i] + y);
        }
    }

    std::cout << dp[n-1] << "\n";
    
    return 0;
}

E 小红的01串(五)

这题也是dp

具体思路我不知道怎么表述(我也是补题的)

直接看代码吧

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()

const int mod = 1e9 + 7;

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    std::string s;

    std::cin >> s;
    std::reverse(all(s));

    int n = s.size();

    s = " " + s;

    std::vector<std::vector<int> > dp(n+1,std::vector<int>(13,0));
    dp[0][0] = 1;

    int tot = 1;

    for(int i = 1 ; i <= n ; i ++) {
        if(s[i] == '?') {
            for(int j = 0 ; j < 13 ; j ++) {
                dp[i][j] += dp[i-1][j];
                dp[i][j] %= mod;

                dp[i][(j + tot)%13] += dp[i-1][j];
                dp[i][(j + tot)%13] %= mod;
            }
        } else {
            if(s[i] == '0') {
                for(int j = 0 ; j < 13 ; j ++) {
                    dp[i][j] += dp[i-1][j];
                    dp[i][j] %= mod;
                }
            } else {
                for(int j = 0 ; j < 13 ; j ++) {
                    dp[i][(j + tot)%13] += dp[i-1][j];
                    dp[i][(j + tot)%13] %= mod;
                }
            }
            
        }

        tot *= 10;
        tot %= 13;
    }

    std::cout << dp[n][0] << "\n";
    
    return 0;
}

转载自博客https://www.cnblogs.com/jiejiejiang2004/p/18612596
博主已同意,我就是博主

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值