C-有大家喜欢的零食吗_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
赛后补题
题面
在某幼儿园中共有 nnn 个小朋友,该幼儿园的老师为这 nnn 个小朋友准备了 nnn 份不一样的零食大礼包。每个小朋友只能选择一个,但老师并不知道小朋友们喜欢什么类型的零食大礼包,因此,老师让小朋友们分别说出了他们喜欢的零食大礼包都有哪些,老师希望能根据小朋友们的叙述来让所有的小朋友们都能吃到他们喜欢的零食。若并非所有的小朋友都能吃到自己满意的零食,请问老师最少还应购买多少份零食大礼包来保证所有的小朋友都能吃到自己满意的零食。题目保证任意一个小朋友都会喜欢这 nnn 种大礼包中的至少一种。
解题思路:
使用回溯。
先建立一个set容器用于存储不同的正整数a。
建立vis数组确保每一次查找不会出现不同的人喜欢同一个零食的情况。
建立gift数组用来存储当前i号小朋友拿到的零食
循环去找不同的人的当前可以选择的零食,如果当前vis为0,说明这次选择不产生冲突,接下去通过gift是否为0判断这个编号的零食有没有被其他人选择。如果被其他人选择,回溯到选择这个的人的编号循环看一下是否这个同学有其他选择,如果有其他选择就更换,让现在这个人选择这个零食。如果没有其它选择,现在的这个同学跳出if判断找下一个喜欢的零食。
如果当前的同学无法选到喜欢的零食返回false,表示需要多买一份零食大礼包。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
set<int>snake[550];//用于存放不同小朋友喜欢的零食编号
int vis[550]={0};//判断当前回溯阶段某个零食是否被选择
int gift[550]={0};//存放哪个零食被哪个人拿走
bool dfs(int k){
for(auto j:snake[k]){
if(vis[j]==0){
//只有当前回溯这个零食没有被占用才能接着做判断,如果都已经被占用了那一定是不符合情况的
vis[j]=1;
if(gift[j]==0||dfs(gift[j])){
//如果零食没有被拿走或者被拿走了但拿走的那个人有其他的选择,当前这个人就选择这个零食。
gift[j]=k;
return true;
}
}
}
return false;//如果循环结束了发现不能选择零食,返回false,做一个特殊记号。
}
signed main() {
int n;
cin>>n;
for(int i=1;i<=n;i++){
int k;
cin>>k;
for(int j=1;j<=k;j++){
int x;
cin>>x;
snake[i].insert(x);
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(!dfs(i)){//如果一个小朋友无法选择零食,就需要多买一包,ans++;
ans++;
}
memset(vis, 0, sizeof vis);
}
if(ans==0)cout<<"Yes"<<endl;
else{
cout<<"No"<<endl<<ans<<endl;
}
return 0;
}
感悟
回溯、深搜还是做得不好,当时做题没有进行更细致的剪枝,超时了。
stl掌握不太好,当时忘记怎么用了,snake开了数组然后内存超了。
F-两难抉择新编_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
赛后补题
题面
解题思路:
一个数a与b异或后得到的数值,再与a异或,得到的结果为b(这个知道了就好做了)
设置数组a和sum=0变量
输入数字的时候就不断存入a,同时和sum进行异或
走两层循环,第一次用来明确ai,第二层用来明确x的范围
sum和ai异或后再分别和(ai*x)以及(ai+x)异或,得到两个数值,比较取大的值
不断这样循环更新,最后就可以出答案了。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int x[9]={0,1,0,1,-1,0,-1,1,-1};
int y[9]={0,0,1,1,0,-1,-1,-1,1};
signed main() {
int n;
cin>>n;
int a[200005];
int sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum=sum^a[i];
}
int res=0;
for(int i=1;i<=n;i++){
for(int x=1;x<=n/i;x++){
int num1=(sum^a[i])^(a[i]+x);
int num2=(sum^a[i])^(a[i]*x);
res=max({num1,num2,res});
}
}
cout<<res<<endl;
return 0;
}
做题感悟
对异或了解不多,比赛的时候还想着把所有数字都拆成二进制,然后发现不知道该怎么取一个ai做改变后再异或。还是知识了解的太少了。
K-图上计数(Easy)_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
赛后补题
题面:
解题思路
没啥特别的思路,就诈骗题...我还没做出来我服了...
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int x[9]={0,1,0,1,-1,0,-1,1,-1};
int y[9]={0,0,1,1,0,-1,-1,-1,1};
signed main() {
int n, m;
cin >> n >> m;
int a=n/2;
int b=n-a;
cout<<a*b<<endl;
return 0;
}
做题感悟:
第n次忘记看范围了,当时提交了一发可能把#define int long long不小心删了,所以我就以为不是这样做...后悔,应该再看一下范围的,以后都要注意范围。
G-旅途的终点_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
赛后补题
题面
做题思路
我感觉有点像贪心?!
输入ai,当i<k的时候,这时候一定能到i个国家
当i>k的时候,无法使用神力了,我们就在目前已经输入的ai中找最小的那个加到sum里
如果sum>=m了,说明k次神力用完后,m也消耗完了,那这个i这就是到不了的那个国家
所以最后输出i-1即可
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
priority_queue<ll, vector<ll>, greater<ll>> q;//使用priority_queue容器可以直接排序
void solve(){
ll n, m, k;
cin >> n >> m >> k;
vector<ll>a(n + 1);
ll s = 0;
for (int i = 1; i <= n; i ++ ){
cin >> a[i];
q.push(a[i]);
if (i > k){
s += q.top();
q.pop();
}if (s >= m){
cout << i - 1;
return;
}
}
cout << n;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int T = 1;
//cin >> T;
while(T -- ) solve();
return 0;
}
做题感悟:
比赛的时候没有用priority_queue而是直接sort(a+1,a+i)进行排序,然后取sum+=a【1】,将a【1】赋值为1e19。