2024.3.1|牛客练习赛122
A.黑白配
B.映射
C.马走日
D.圆
E.外向树
F.括号匹配
心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。
黑白配
题目:
“黑白配”是一款家喻户晓的小游戏。每个人亮出手心或手背,亮出手心的为一队,亮出手背的为一队。
有 n 个学生在玩“黑白配”。他们想知道分组结果是否公平,请求出两队人数之差的绝对值。
为了求出最佳配队,他们会进行 T 轮游戏。
输入描述:
第一行两个整数 ,T,n。接下来 T 行,每行 n 个数。第 i 个数为 0
表示第 i 个学生亮出手心,第 i 个数为 1
则表示第 i 个学生亮出手背。
输出描述:
输出为 T 行,即每轮游戏两队人数之差的绝对值。
示例1
输入
3 5
0 0 0 0 0
1 0 1 1 0
1 1 1 1 0
输出
5
1
3
备注:
对于所有数据1≤T,n≤100。
注意:
A题是签到题,所给轮数T和每轮人数n的数据范围极小,可以暴力。
实践代码:
void solve(){
int t,n;cin>>t>>n;
vector<int> a(n);
while(t--){
int n1=0,n2=0;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++){
if(a[i]==0) n1++;//统计亮手心的人数
else n2++;//统计亮手背的人数
}
cout<<abs(n2-n1)<<endl;//两队人数之差
}
}
优化:
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;
}
}
映射
题目:
给出两个长度为 n 的序列 a,b,值域为 1 到 n。
询问能不能构造出一个序列 p,满足 ∀1≤i≤n,pai=bi。
输入描述:
第一行一个数 T,表示数据组数。
每组数据三行:
第一行一个整数 n。
第二行 n 个整数,表示数组 ai 。
第三行 n 个整数,表示数组 bi 。
输出描述:
输出为 T 行,即每组数据的答案。
若可以构造输出 Yes,否则输出 No。
示例1
输入
3
5
1 2 2 3 4
4 3 3 2 2
5
1 2 2 3 4
1 2 3 4 5
5
1 2 3 4 5
5 4 3 2 1
输出
Yes
No
Yes
备注:
对于所有数据 1≤T≤10,1≤n≤105, 1≤ai ,bi ≤n。
补充:
两个非空集合A与B间存在着对应关系f,而且对于A中的每一个元素a,B中总有唯一的一个元素b与它对应,就这种对应为从A到B的映射,记作f:A→B。——百度百科
注意:
B题大意为当a数组中的两元素相等时,它们作为p数组的下标时所对应的b数组的值一定相等,才能成为映射关系(都满足则输出“Yes”),否则不满足映射关系(输出“No”)。但是由于p并不一定排列,如果我们暴力来求区间内a[i]=a[i+1]且b[i]!=b[i+1]的情况时时间复杂度极高,很有可能会TLE,且本题需要通过a映射b的值,我们就可以用结构体排序来做。
实践代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e6+10;
const int mod = 998244353;
struct st{
int a,b;
}x[N];
bool cmp(st a,st b){
return a.a<b.a;
}
void solve(){
int n,flag=1;cin>>n;
vector<int> a(n);
vector<int> b(n);
for(int i=0;i<n;i++) cin>>x[i].a;
for(int i=0;i<n;i++) cin>>x[i].b;
sort(x,x+n,cmp);
for(int i=0;i<n-1;i++){
if(x[i].a==x[i+1].a&&x[i].b!=x[i+1].b) flag=0;
else continue;
}
if(flag==1) cout<<"Yes"<<endl;
else if(flag==0) cout<<"No"<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
优化:
int a[N],b[N];
void solve(){
int n; cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)cin>>b[i];
map<int,int> mp;//map本就用来表示映射关系(键值对)
for(int i=1;i<=n;++i){
if(mp[a[i]]&&mp[a[i]]!=b[i]){
cout<<"No"<<endl;
return ;
}else mp[a[i]]=b[i];
}
cout<<"Yes"<<endl;
}
在map的键值对<key,value>中,一个key唯一
对应一个value,不同的key可能对应相同的value,类似函数的自变量x和因变量y的关系
马走日
题目:
给出一个 n×m 的点阵,第 i 行第 j 列的点为(i,j)。
初始时,马被放置在 (1,1) 位置上。众所周知马走日,形式化来说,若马位于(x,y),其可以跳到 (x+1,y+2),(x−1,y+2),(x+1,y−2),(x−1,y−2),(x+2,y+1),(x−2,y+1),(x+2,y−1),(x−2,y−1) 其中之一。
注意,马的位置 (x,y) 必须时刻保持 1≤x≤n,1≤y≤m。
询问在 n×m 的点阵上,马能跳到多少个位置。
输入描述:
第一行一个整数 T,表示询问组数。
接下来 T 行,每行两个数 n,m,表示一组询问。
输出描述:
输出为 T 行,即每组数据的答案。
示例1
输入
3
3 3
2 3
100 100
输出
8
2
10000
备注:
对于所有数据,1≤T≤105, 1≤n,m≤109。
注意:
C题如果你不看n,m的范围,直接开二维数组咔咔整,那么离MLE也就不远了。所以静下心来想一想,我们可不可以穷举出不同棋盘规格下马能走的位置的所有可能性和规律呢,答案是显然的。
实践代码:
void solve()
{
int n,m;
cin>>n>>m;
if(n==1||m==1||(n==2&&m==2))
{
cout<<1<<endl;
return ;
}
if(n==2)
{
cout<<(m+1)/2<<endl;
return ;
}
if(m==2)
{
cout<<(n+1)/2<<endl;
return ;
}
if(n==3&&m==3)
{
cout<<8<<endl;
return ;
}
cout<<n*m<<endl;
}
圆
题目:
输入描述:
输出描述:
示例1
输入
输出
说明
示例2
输入
输出
说明
**注意**: ====外向树
题目:
输入描述:
输出描述:
示例1
输入
输出
注意:
实践代码:
括号匹配
题目:
输入描述:
输出描述:
示例1
输入
输出
示例2
输入
输出
注意:
实践代码:
心有猛虎,细嗅蔷薇。再见了朋友~