牛客周赛91题解

牛客周赛91

https://ac.nowcoder.com/acm/contest/108038#question

A.while

https://ac.nowcoder.com/acm/contest/108038/A

签到题:只需要判断当前字符串与while有多少个位置上的字符不相同即可。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;cin>>s;
    int ans=0;
    if(s[0]!='w') ans++;
    if(s[1]!='h') ans++;
    if(s[2]!='i') ans++;
    if(s[3]!='l') ans++;
    if(s[4]!='e') ans++;
    cout<<ans;
    return 0;
}

B.token

https://ac.nowcoder.com/acm/contest/108038/B

签到题,用前缀和解决即可。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int main()
{
    int n;cin>>n;
    vector<LL> a(n+1,0),s(n+1,0);
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
    LL ans=0;
    for(int i=1;i<=n;i++){
        if(i<=9) ans=max(ans,s[i]);
        else ans=max(ans,s[i]-s[i-10]);        
    }
    cout<<ans;
    return 0;
}

C.小苯的逆序对和

https://ac.nowcoder.com/acm/contest/108038/C

思路:预处理出前i个数中最大的数的值p[i],然后枚举下标\(i\),若p[i-1]>a[i],也就是说,下标i前面的值有>a[i]的部分,那么可以构成逆序对,因为要求最大的a[i]+a[j],故而我们处理出前i个数中最大的值即可。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n;cin>>n;
    //预处理前i个数中的最大值
    vector<int> a(n+1,0),p(n+1,0);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        p[i]=max(p[i-1],a[i]);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(p[i-1]>a[i]) ans=max(p[i-1]+a[i],ans);
    }
    cout<<ans<<"\n";
}

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

D.数组4.0

https://ac.nowcoder.com/acm/contest/108038/D

思路:将数组中的元素进行排序以后,计算"段数",那么答案就是"段数"-1,怎么计算段数呢?当我们以一个数x新开一段时,意味着x-1在数组中必然不存在,那么我们只需要用map来存储每个数出现的频率,(至于为什么用map,不用set,后面有解释。)如果x-1出现的频率为0,那么就新开一段。

那么为什么我们使用map而不使用set呢?我们有一种特殊情况,类似下列样例:

[1,2,4,4,6,7,8]这个样例,我们需要在2,4之间连接一条边,也需要在4,44-6之间连一条边,也就是说:当x+1在数组中不存在时,我们需要将所有的x之间连接起来,将所有x连接起来的代价是:x出现的频率-1

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n;cin>>n;
    map<int,int> mp;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        mp[x]++;
    }
    int ans=0;
    for(auto & [x,y] : mp){
        //x-1不存在,就新开一段
        if(!mp.count(x-1)){
            ans++;
            //若x+1不存在,那么需要将所有的x自行连接起来...
            if(!mp.count(x+1)) ans+=y-1;
        }
    }
    //答案为"段数"-1;
    cout<<ans-1<<"\n";
}
int main()
{
    int t=1;cin>>t;
    while(t--) solve();
    return 0;
}

E.小苯的矩阵反转

https://ac.nowcoder.com/acm/contest/108038/E

思路:如果给我们一个01矩阵,让我们判断是否能变成全0矩阵,这样或许有点麻烦,有很多种情况需要讨论,那么我们不妨反过来思考,给我们一个全0矩阵,经过这几种操作之后,能够变成什么样的矩阵,然后将这个矩阵和我们原本的01矩阵进行匹配,如果匹配成功,那么就输出YES,否则输出NO;

那么给我们一个01矩阵,进行这几种操作以后,可以有四种情况:

  1. 选择全0的一行(列)进行翻转两次,得到的矩阵还是全0矩阵
  2. 选择全0的两行(这两行不同)分别翻转一次,得到的矩阵是:只有两行全是1,其余行都是0;
  3. 选择全0的两列(这两列不同)分别翻转一次,得到的矩阵是:只有两列全是1,其余列都是0;
  4. 选择一行和一列进行操作,翻转一次。那么得到的会是一个十字架类型的图形,除了交叉点,其余点都是1;

那么如何写代码进行判断呢?

  1. 全0的情况很容易判断,只需要数字符1的个数c1,若c1==0,那么这个01矩阵原本就是全0矩阵

  2. 选择两行进行翻转,那么翻转以后,得到的矩阵中的1的个数必然为m*2,并且其他行都是0,我们只需要用一个变量Cr来记录全是0是行的个数,若Cr==2 && c1==m*2,那么就符合我们这种情况。

  3. 选择两列翻转,与第二条同理。我们用Cc来记录 全0的列数的个数,若Cc==2 && c1==n*2,那么就符合情况

  4. 十字架类型的图形,这种情况,因为交点是0,那么我们只需要枚举0的位置,假设当前行列的位置分别为i,j。那么我们只需要判断第i行中1的个数是否为m-1以及第j列中1的个数是否为n-1,以及字符1的个数为n+m-2;如果三条都满足,那么就符合这种情况。在这里我们需要用r[i]来记录第i行中1的个数,还需要用c[j]来记录第j列中1的个数

cpp 复制代码
//正难则反
//考虑四种情况
//1.原本就是全0
//2.有两列/行为1
//3.有一个十字架型的形状(除了交点以外都是1);

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n,m;cin>>n>>m;
    vector<string> a(n);
    //r[i]表示第i行中1的个数,..c[i]表示第i列中1的个数
    vector<int> r(n),c(m);
    for(int i=0;i<n;i++) cin>>a[i];
    //算1的个数
    int c1=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(a[i][j]=='1'){
                c1++;
                //第i行,第j列
                r[i]++;
                c[j]++;
            }
        }
    }
    //计算全是1的行数的个数
    int Cr = 0;
    for(int i = 0; i < n; i++) {
        Cr += (r[i] == m);
    }
    //计算全为0的列数的个数
    int Cc = 0;
    for(int i = 0; i < m; i++) {
        Cc += (c[i] == n);
    }
    //还有类似十字架的图形,枚举0的位置..那么那行的1的个数为m-1,那一列的1的个数为n-1..且总的1的个数为n+m-2;
    bool flag=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(a[i][j]=='1') continue;
            if(r[i]==m-1&&c[j]==n-1&&c1==n+m-2) flag=true;
        }
    }
    //满足一种情况,那么就输出YES,否则为NO;
    if(c1==0||(c1==2*m && Cr==2)||(c1==2*n && Cc==2)||flag) cout<<"YES\n";
    else cout<<"NO\n";
}
int main()
{
    int t=1;cin>>t;
    while(t--) solve();
    return 0;
}

F.小苯的因子查询

https://ac.nowcoder.com/acm/contest/108038/F

有待更新....