2024.3.10|牛客周赛 Round 36

2024.3.1|牛客周赛 Round 36

A.小红的数位删除
B.小红的小红矩阵构造
C.小红的白色字符串
D.小红走矩阵
E.小红的小红走矩阵
F.小红的好子串询问

心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。
在这里插入图片描述

小红的数位删除

题目
小红拿到了一个正整数,她希望删除该正整数的最后三位,你能帮帮她吗?
输入描述:
一个正整数n
1000≤n≤109
输出描述:
删除最后三位后形成的正整数。
示例1
输入
12345
输出
12

注意
A题是签到题。用.substr()更快。

实践代码:

void solve(){
    string s;cin>>s;
    int n;cin>>n;
    cout<<s.substr(0,s.length()-3);
}

优化:

void solve()
{
    int t,n;cin>>t>>n;
    while(t--){
        int c = 0;
    for (int i = 1; i <= n; i++){
        int x;cin>>x;
        if(x)c++;
        else c--;
    }
    cout<<abs(c)<<endl;
    }
}

小红的小红矩阵构造

题目
小红拿到了一道题,题目设定如下:

https://ac.nowcoder.com/acm/problem/268977

小红希望你构造一个n行m列的矩阵,满足所有元素之和恰好等于x,且每行、每列的异或和全部相等。你能帮帮她吗?

【样例输入】
4 4 4
【样例输出】
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

小红希望你判断她的输出是否符合要求,你能帮帮她吗?

输入描述:
第一行输入三个正整数n,m,x,代表小红做这道题的输入部分。
接下来的n行,每行输入m个非负整数,代表小红构造的矩阵。
1≤n,m≤100
0≤x≤109

保证x是偶数。小红输出的元素保证不超过109

输出描述:
如果小红成功通过了本题,则输出"accepted"。否则输出"wrong answer"
示例1
输入
4 4 14
1 2 3 0
1 2 2 1
0 0 1 1
0 0 0 0
输出
accepted
示例2
输入
4 4 4
1 1 1 1
0 0 0 0
0 0 0 0
0 0 0 0
输出
wrong answer
示例3
输入
4 4 4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
输出
wrong answer

注意
B题首先要了解异或,且本题数据范围不大,可以暴力。
首先判断矩阵元素总和,其次判断每行和每列的异或和是否相等。

补充:

异或:异或,是一个数学运算符,英文为exclusive OR,缩写为xor,应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:a⊕b = (¬a ∧ b) ∨ (a ∧¬b)
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位。
参与运算的两个值,如果两个相应bit位相同,则结果为0,否则为1。
即:
0^0 = 0,
1^0 = 1,
0^1 = 1,
1^1 = 0
求a,b,c,d的异或和a ^b ^c ^d

实践代码:

void solve(){
    int n,m,x,sum=0;cin>>n>>m>>x;
    vector<vector<int>> a(n+1,vector<int>(m+1));
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
            sum+=a[i][j];
        }
    }
    if(sum!=x) {cout<<"wrong answer";return;}
    int flag=0;//记录第一行的异或和
    
    for(int i=0;i<n;i++){//按行判断
        int ans=0;
        for(int j=0;j<m;j++){
            ans^=a[i][j];
        }
        if(i==0) flag=ans;//将第一行的元素异或和存在flag中,用于后续比较
        else if(ans!=flag) {cout<<"wrong answer";return;}
    }
    
    for(int j=0;j<m;j++){
        int ans=0;
        for(int i=0;i<n;i++){
            ans^=a[i][j];
        }
        if(ans!=flag) {cout<<"wrong answer";return;}
    }
    cout<<"accepted";return;
}

小红的白色字符串

题目

小红拿到了一个字符串,她准备将一些字母变成白色,变成白色的字母看上去就和空格一样,这样字符串就变成了一些单词。
现在小红希望,每个单词都满足以下两种情况中的一种:
1.开头第一个大写,其余为小写(长度为 1 的大写字母也是合法的)。
2.所有字符全部是小写。
小红想知道,最少需要将多少字母变成白色?
输入描述:
一个仅包含大小写字母的字符串。
字符串长度不超过200000
输出描述:
将字母变成白色的最小数量。
示例1
输入
aDRRanko
输出
2
说明
将第二个和第三个字母变成白色即可,字符串变成 “a Ranko”

注意
C题,这道题有两种情况且让满足其一,我们可以清楚大写字母属于特殊情况要加以判断,且第一个字母不论大小写均合法,所以直接从第二个字母开始判断大小写,如果大写的话就涂成空白。
特殊情况:注意如果此时此位置为大写字母且前一个位置已涂成空白(说明此时此处为这一字串的开头字母,而开头字母大写满足第一个要求),我们不能再涂。

实践代码:

void solve(){
    string s;cin>>s;
    int cnt=0;
    for(int i=1;i<s.length();i++){
        if(s[i]>='A'&&s[i]<='Z'&&s[i-1]!=' '){
            s[i]=' ';
            cnt++;
        }
    }
    cout<<cnt;
}

小红走矩阵

题目

小红来到了一个n∗m的矩阵,她初始站在左上角,每次行走可以按“上下左右”中的一个方向走一步,但必须走到和当前格子不同的字符,也不能走到矩阵外。

小红想知道,从左上角走到右下角最少需要走多少步?

输入描述:
第一行输入两个正整数n,m,用空格隔开。代表矩阵的行数和列数。
接下来的n行,每行输入一个长度为m的、仅由小写字母组成的字符串,用来表示矩阵。
1≤n,m≤1000

输出描述:
如果无法到达右下角,则输出-1。
否则输出一个整数,代表行走的最小步数。

示例1
输入
3 4
abbc
accd
bcee

输出
9

说明
在这里插入图片描述

注意
D题是一个典型的bfs+最短路径(二维数组存储)。

实践代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1010;
char a[N][N];
bool vis[N][N];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,1,-1};
int d[N][N];//更新最短路径
struct node{
    int x,y;
};

void bfs(int n,int m){
    queue<node> q;
    q.push({0,0});
    vis[0][0]=true;
    while(!q.empty()){
        node tmp=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int tx=tmp.x+dx[i],ty=tmp.y+dy[i];
            if(tx<0||tx>n||ty<0||ty>m||a[tx][ty]==a[tmp.x][tmp.y]||vis[tx][ty])
                continue;
            d[tx][ty]=d[tmp.x][tmp.y]+1;//往前走一步就在上一步的基础上+1
            q.push({tx,ty});//将当前点位存起来
            vis[tx][ty]=true;
        }
    }
}

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

    bfs(n-1,m-1);
    if(vis[n-1][m-1]) cout<<d[n-1][m-1];
    else cout<<-1;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

小红的小红走矩阵

题目

小红在出题“小红的走矩阵”时,在数据生成的环节发现了一些问题。
如果直接随机生成一个矩阵,那么结果大概率可以直接输出 n+m−2。
如果直接生成极限数据,那么结果也将是跑完整个矩阵,因此可以直接输出 n∗m−1。
为了避免以上的情况骗到分,于是小红想到了另一个方案:先随机生成一个从 (1,1) 到 (n,m) 的路径,再将路径以外的矩阵的部分全部填成同一个字符。这样一来看似数据确实强,答案并不固定,但实际上也有非常明显的弊端,因为矩阵中大部分都是同一个字符,且这个字符在路径之外,因此选手可以通过“矩阵中是否存在绝对众数”来判断数据是否是这样的数据。

因此小红现在在数据生成的问题上犯了难,她希望小苯帮她来完成本题数据的生成,即请你来代替小苯构造出本题较强的数据。
使得所有的数据都能满足以下的所有条件:

  1. 直接输出 n+m−2 会返回答案错误,换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 n+m−2。
  2. 直接输出 n∗m−1 也会返回答案错误,换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 n∗m−1。
  3. 生成的矩阵中,不存在“绝对众数”。(即,没有任何字符的出现次数大于 n∗m/2 向上取整)
  4. 生成的矩阵必须能从 (1,1) 走到 (n,m),换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 −1。

输入描述:
输入包含一行两个正整数 n,m (3≤n,m≤103 ),分别表示需要生成的矩阵的大小,以空格分割。
输出描述:
输出包含一个 n 行 m 列 的字符矩阵,满足题目所述的要求,且仅由小写英文字母构成。(如果有多种方案,输出任意即可)
示例1
输入
3 4
输出
abbc
accd
bcee

说明
在这里插入图片描述
备注
在这里插入图片描述

注意
E题为构造题。
第一个条件:不能n+m-2即不能直来直去的构造。
第二个条件:n*m-1不很好构造,可以忽略。
第三个条件:不存在“绝对众数”,避免构造出来一种路径后,剩余其他都用同一个字母。
第四个条件:必须有一条最短路径能从左上角到达右下角。
所以我们可以这样构造,即从第一行直走到头,再从最后一列直走到倒数第2个点,之后左转走一个点,向下走一个点,再向右走到终点(避免第2个条件不成立,走一个S型)

在这里插入图片描述

实践代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int a[1010][1010];
void solve(){
    int n,m;cin>>n>>m;
    /*前两行构造abab...使之只能向右走到头*/
    for(int i=0;i<2;i++){//前两行
        for(int j=0;j<m;j++) a[i][j]=j%2+1;//abab...构造
    }
    /*使第二行之后的每行最后两个位置元素相等,使之走到头后能向下走*/
    for(int i=1;i<m;i++){//第二行
        a[i][m-1]=a[i][m-2]=(i+m+1)%2+1;//根据行数i和m的奇偶性来赋值,如果m为奇数,则后面两个表达式需是b,反之亦然
    }
    //需要走s型,强制改一下最后两行的最后两个所经路径位置的元素
    a[n-1][m-2]=4;//终点左边的位置
    a[n-2][m-1]=3;//终点上边的位置
    a[n-1][m-1]=3;//终点位置,与上边元素相等使之不能一步到达
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(!a[i][j]) a[i][j]=rand()%26+1;//剩下的位置随机数,使之避免“绝对众数”
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cout<<(char)(a[i][j]-1+'a');
        }
        cout<<endl;
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

小红的好子串询问

题目

小红定义一个字符串是“好串”,当且仅当该字符串不包含长度不小于 2 的回文子串。
现在小红拿到了一个仅包含"red"三种字符的字符串,她有如下两个操作:
· 输入 1 x chr:将第x个字符修改为chr
· 输入 2 l r:询问第l个字符到第r个字符的子串再修改最少多少个字符可以变成好串(每次修改后也必须是"red"三种字符中的一种)。
你能帮帮她吗

输入描述:
第一行输入两个正整数
n,q,代表字符串长度、操作次数。
第二行输入一个仅包含长度为n的、"red"三种字符的字符串。
接下来的q行,每行输入一个操作1 x chr或者2 l r,含义如上所述。
1 ≤ n , q ≤ 105
1 ≤ x ≤ n
1 ≤ l ≤ r ≤ n
chr∈ ‘r’,‘e’,‘d’
保证至少有一次操作 2。

本题有5%的数据满足:1≤n,q≤5
有25%的数据满足:1≤n,q≤2000
另外有20%的数据满足:所有操作均为操作2。

输出描述:
对于每个操作 2,输出一个整数表示答案,即子串变成好串的最小修改次数。
示例1
输入
5 3
deder
2 2 4
1 3 r
2 1 3
输出
1
0
说明
第一次询问的子串是"ede",将第一个或者第三个字符修改为’r’可以变成好串。
第二次询问的子串是"der",是好串。

注意
F题用树状数组和前缀和。

实践代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
/*长度为n的回文串<=>一定包含一个长度为n-2的回文子串
逆否命题:不包含一个长度为n-2的回文子串<=>不是一个长度为n的回文串
*/
string str[6] = {"red","rde","edr","erd","der","dre"};
int t[404040][6];//树状数组
void add(int x,int id,int p){
    for(int i=x;i<=2e5;i+=i&-i){
        t[i][id]+=p;
    }
}
int ask(int x,int id){
    int res=0;
    for(int i=x;i>0;i-=i&-i){
        res+=t[i][id];
    }
    return res;
}
int ask(int l,int r,int id){
    int res=ask(r,id);
    if(l>1) res-=ask(l-1,id);
    return res;
}
void solve(){
    int n,q;cin>>n>>q;
    string s;cin>>s;
    s=' '+s;
    for(int i=1;i<=n;i++){
        for(int j=0;j<6;j++){
            if(s[i]!=str[j][i%3]) add(i,j,1);
        }
    }
    while(q--){
        int op;cin>>op;
        if(op==1){
            int x;char c;cin>>x>>c;
            for(int i=0;i<6;i++){
                if(s[x]!=str[i][x%3]) add(x,i,-1);
                if(c!=str[i][x%3]) add(x,i,1);
            }
            s[x]=c;
        }
        else{
            int l,r;
            cin>>l>>r;
            int res=1e9;
            for(int i=0;i<6;i++){
                res=min(res,ask(l,r,i));
            }
            cout<<res<<endl;
        }
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

心有猛虎,细嗅蔷薇。再见了朋友~

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值