2022CUST上学期训练赛8 补题A、D、L

2022CUST上学期训练赛8

A:Edit Distance构造、思维:Mid–

题意

给你一个01字符串,求另一个相同长度的字符串,使它两的编码距离>=len/2。

思路

  • 当字符串中0与1的数量不相等时:
    • 若1多,输出000000…
    • 若0多,输出111111…
  • 当字符串中0的个数和1的个数相等时:利用动态规划求编码距离的思想
    • 当s[0]='1’时,输出0111111…
    • 当s[0]='0’时,输出1000000…
    • 原因:
      • 因为第一位不同,那么s与t的编码距离edit(s[1…n],t[1…n])有以下三种情况:下列的后续状态很容易求出来
        1. 替换情况(替换第一位以致相同+后续的状态):edit(s[1…len],t[1…len])+1=len/2+1(后续状态=len/2)
        2. 插入情况(将t[0]插入到s的前面+后续状态):edit(s[0…len],t[1…len])+1=len/2+1(后续状态=len/2-1+1需要一个删除操作所以要+1
        3. 删除情况(将s[0]删除+后续状态):edit(s[1…len],t[0…len])+1=len/2+1(后续状态=len/2-1+1需要一次删除操作所以要+1

代码

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

int main()
{
    string s;
    cin >> s;
    int num0 = 0, num1 = 0;
    for (int i = 0; i < s.length(); i++)
    {
        if (s[i] == '0')
            num0++;
        else
            num1++;
    }
    if (num1 > num0)
    {
        for (int i = 0; i < s.length(); i++)
            cout << 0;
    }
    else if (num1 < num0)
    {
        for (int i = 0; i < s.length(); i++)
            cout << 1;
    }
    else if (num1 == num0)
    {
        if (s[0] == '1')
        {
            cout << 0;
            for (int i = 0; i < s.length() - 1; i++)
                cout << 1;
        }
        else
        {
            cout << 1;
            for (int i = 0; i < s.length() - 1; i++)
                cout << 0;
        }
    }
}

Icy Land思维:Mid–

题意

'#‘表示干地,’.'表示冰地

如果在冰地上往一个方向走,就会一直走直到走到干地或者边缘

你可以将冰地改成干地,问最小修改次数使得不管在哪个地方开始都可以遍历所有的点

思路

首先,不管从哪个地方开始可以转换成从(1,1)开始,因为哪个地方开始都可以走到(1,1)。

接下来进行分类讨论

  1. (n<=2&&m<=2)那么不用修改
  2. (n==1&&m>2)||(n==2&&m>2):那么需要保证2到m-1每一列都有干地
  3. (n>2&&m==1)||(n>2&&m==2):那么需要保证2到n-1每一行都有干地
  4. 若上述都不是:
    1. 需要保证a[2...n-1][2...m-1]全是干地
    2. 并且要保证四周至少有一个点可以"着路":就是a[1][2...m-1],a[n][2...m-1],a[2...n-1][1],a[2...n-1][m]中至少有一个干地,因为这样才能从四周走到中间的干地

代码

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

const int maxn=5005;
int n,m;
int ans;
char a[maxn][maxn];

void solve(){
    if(n<=2&&m<=2){
        cout<<0;
        return;
    }
    ans=0;
    if(n==1&&m>2){
        for(int i=2;i<=m-1;i++)if(a[1][i]=='.')ans++;
        cout<<ans;
        return;
    }
    ans==0;
    if(m==1&&n>2){
        for(int i=2;i<=n-1;i++)if(a[i][1]=='.')ans++;
        cout<<ans;
        return;
    }
    ans=0;
    if(n==2&&m>2){
        for(int i=2;i<=m-1;i++)if(a[1][i]=='.'&&a[2][i]=='.')ans++;
        cout<<ans;
        return;
    }
    if(m==2&&n>2){
        for(int i=2;i<=n-1;i++)if(a[i][1]=='.'&&a[i][2]=='.')ans++;
        cout<<ans;
        return;
    }
    ans=0;
    for(int i=2;i<=n-1;i++){
        for(int j=2;j<=m-1;j++){
            if(a[i][j]=='.')ans++;
        }
    }
    bool judge=false;
    for(int i=2;i<=n-1;i++){
        if(a[i][1]=='#'||a[i][m]=='#')judge=true;
    }
    for(int i=2;i<=m-1;i++){
        if(a[1][i]=='#'||a[n][i]=='#')judge=true;
    }
    if(!judge)ans++;
    cout<<ans;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)cin>>a[i][j];
    }
    solve();
}

Binary String贪心、思维:Mid–

题意

将一个前缀0的二进制字符串删除任意字符多次,使其的10进制表示法<=k。

问删除的最小次数,并且删除后的字符串不能含有前缀0

思路

假设给定字符串s2的10进制表示法我为s10

l e n = ∣ s 2 ∣ − ∣ k ∣ ,二进制位数差 len=|s_2|-|k|,二进制位数差 len=s2k,二进制位数差

贪心:为了以尽可能少的删除次数使得s10尽可能小,就把第一个1后面的1逐个删除(注意第一个1不能删除,保证不会出现前缀0),直到|s2|与|k|的二进制位数相等或者1删完:

  • 当1删完之后, ∣ s 2 ∣ > = ∣ k ∣ |s_2|>=|k| s2>=k,此时s2=1000000…,那么结果就是在删除0直到二者二进制位数相等:共len次操作
  • 否则,此时1为删完且 ∣ s 2 ∣ = ∣ k ∣ |s_2|=|k| s2=k,那么就直接判断此时s10与k的大小
    • 若s10>k,那么在删一位:共len+1次操作
    • 若s10<=k,那么达成目的:共len次操作

代码

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

int main(){
    string s;
        cin>>s;
        int num0=0,num1=0;
        for(int i=0;i<s.length();i++){
            if(s[i]=='0')num0++;
            else num1++;
        }
        if(num1>num0){
            for(int i=0;i<s.length();i++)cout<<0;
        }
        else if(num1<num0){
            for(int i=0;i<s.length();i++)cout<<1;
        }
        else if(num1==num0){
            if(s[0]=='1'){
                cout<<0;
                for(int i=0;i<s.length()-1;i++)cout<<1;
            }
            else {
                cout<<1;
                for(int i=0;i<s.length()-1;i++)cout<<0;
            }
        }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值