牛客周赛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,4
和4-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矩阵,进行这几种操作以后,可以有四种情况:
- 选择全0的一行(列)进行翻转两次,得到的矩阵还是全0矩阵
- 选择全0的两行(这两行不同)分别翻转一次,得到的矩阵是:只有两行全是1,其余行都是0;
- 选择全0的两列(这两列不同)分别翻转一次,得到的矩阵是:只有两列全是1,其余列都是0;
- 选择一行和一列进行操作,翻转一次。那么得到的会是一个十字架类型的图形,除了交叉点,其余点都是1;
那么如何写代码进行判断呢?
-
全0的情况很容易判断,只需要数字符1的个数
c1
,若c1==0
,那么这个01矩阵原本就是全0矩阵 -
选择两行进行翻转,那么翻转以后,得到的矩阵中的1的个数必然为
m*2
,并且其他行都是0,我们只需要用一个变量Cr
来记录全是0是行的个数,若Cr==2 && c1==m*2
,那么就符合我们这种情况。 -
选择两列翻转,与第二条同理。我们用
Cc
来记录 全0的列数的个数,若Cc==2 && c1==n*2
,那么就符合情况 -
十字架类型的图形,这种情况,因为交点是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
有待更新....