事后诸葛亮,脑子不好使了
A-造数_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
题意:给定一个整数 𝑛n ,你可以进行以下三种操作:+1 , +2 ,*2,问至少多少次操作可以将0转为n;
题解:对于一个数,如果它是奇数就减一,如果是偶数,就除以二,知道n等于0为止。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005],op=0;
signed main(){
int n;
cin>>n;
while(n){
if(n%2==0)n/=2;
else {
n--;
}
op++;
if(n==1)break;
// cout<<n<<endl;
}
cout<<op<<endl;
return 0;
}
B-爱探险的朵拉_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
其实我到现在还不知道为什么会超时,我觉得应该不会,我的思路是遍历每一个未访问的点,如果一个点是没有被访问的,就记录它的循环周期是多长,顺便把这个周期上的所有点标记为已访问。。。。。我觉得时间复杂度是O(n)但是T了,如果有谁知道可以告诉我嘛 —_—;
只是我错误的代码(TLE):
#include<bits/stdc++.h>
using namespace std;
int p[100005];
#define int long long
int ans=0;
int vis[100005];
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i];
}
for(int i=1;i<=n;i++){
int be=i;
int cur=i;
vis[i]=1;
int num=1;
cur=p[cur];
if(vis[cur]==0){
while(cur!=be){
vis[cur]=1;
num++;
cur=p[cur];
}
ans=max(ans,num);
}
}
cout<<ans<<endl;
return 0;
}
正确的做法:拓扑排序(半年前的知识点的了,记不得了T-T)
拓展:(拓扑排序):入度为0的结点依次删掉排序。
拓扑排序可以判断有向图中是否有环。可以生成拓扑序列;若序列中的元素个数等于n,则有拓扑序,否则有环
算法的核心:用队列维护一个入度为0的节点的集合。
1,初始化,队列q压入所有入度为0的点;
2,每次从q中取出一个点x放入数组tp;
3,然后将x的所有出边删除,若将边(x,y)删除后,y的入度变为0,则将y压入q中;
4,不断重复2,3,过程,知道队列q为空;
这题难度有点大,晚点补
C-有大家喜欢的零食吗_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
题意,每个小朋友都有自己喜欢的n种零食,要让每个小朋友都得到互不相同的零食,求最少还需要买多少零食?
二部图最大匹配:匈利亚算法:
(有权):领接矩阵,给每一行减去其最小值,使每一行至少有一个0;然后给每一列减去最小值,使每一列至少有一个0,。
然后要做循环:
1.用尽量少的线覆盖所有的0;
2,决定是否终止循环。假如用的线条数等于n(节点数),就终止循环,如果小于n就继续循环
3,在矩阵中产生更多的0;,在所有未被覆盖的元素中找到最小的值,记为k
,然后把所有为被覆盖的元素都减去k;还需要把k加到红线交叉的地方。
结束循环后,n个0代表图中的n条边,每个0对应一条边,要在n个0里边选择m(顶点数)代表最大小匹配,最大匹配操作只需要将数据取反即可;
(无权):通过不停地找增广路来增加匹配边。找不到增广路时,达到最大匹配。可以用DFS或者BFS来实现。
算法:
链上前向星(存边):
就是链接表:
struct E
{
int to;
int w;
int next;
}Edge[maxm];
for(int i=Head[u];~i/*(i==-1)指向空终止循环*/;i=Edge[i].next){
int v=Edge[i].to;
int w=Edge[i].w;
}
void AddEdge(int u,int v,int w){
//前面三句是创造一个空结点,给新节点进行初始化
Edge[tot].to=v;
Edge[tot].w=w;
Edge[tot].next=Head[u];//将空结点指向所连接的Head[u];
Head[u]=tot++;
}
以上内容是链式向前星的内容。
无权最大匹配;
流程:
边e[i] 存第i条出边{v,ne}
表头h[u]:存u点的第一条出边
标记vis[v]:存女生v是否访问
配对match[v]:存女生v的男友;、
匈牙利算法:男女相亲,男选女可占可让,贪心配对:
1.枚举n个男生,
每轮vis[]初始化为0,(即女生皆可选),
深搜若能配成对,ans+1;
2.枚举男生u的心仪女孩v,
(1)若女孩已标记就逃过
(2)若女孩没男朋友,则配成对
若女孩的男友可以让出,则配成队。
(3)否则,枚举u的下一个心仪女孩
3.枚举完u的心仪女孩都不能配成对,则return 0;
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k,m,a,b,ans;
#define M 10000
#define N 200005
struct edge{
int v,next;
}e[M];
int h[N],idx;
int vis[N],match[N];
void add(int a,int b){
e[++idx]={b,h[a]};
h[a]=idx;
}
bool dfs(int u){
for(int i=h[u];i;i=e[i].next){
int v=e[i].v;//枚举该男孩的心动女孩
if(vis[v])continue;
vis[v]=1;//先标记这个女孩
if(!match[v]/*如果该女孩没有对象*/||/*枚举此女孩的男友还有没有可选的女孩*/dfs(match[v])){
match[v]=u;//配成对
return 1;
}
}
return 0;
}
signed main(){
cin>>n>>m>>k;
for(int i=0;i<k;i++){
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++){//男选女,枚举每一个男生
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;//走进男生i;
}
cout<<ans<<endl;
}
题解: 此题不知到为什么用链式向前星会超时,可能用错了,因为对他还是不太熟悉,所以此题用邻接图来做;储存一个邻接表,遍历每一个孩子,然后遍历每一个孩子喜欢的零食,如果该零食没有被选择,则这个零食就和该孩子匹配,或者说,如果该零食被选择,就查找持有该零食的孩子是否还有其他零食可以选择,如果有,则持有该零食的孩子就把零食让给现在所遍历到的孩子,然后绑定零食和孩子之间的关系。最后,如果每个孩子都有自己的零食,就输出:Yes,否者输出n-ans;
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k,m,a,b,ans;
#define M 10000
#define N 200005
int vis[505],match[505];
int e[505][505];
bool dfs(int u){
for(int i=1;i<=n;i++){
if(!vis[i]&&e[u][i]){
vis[i]=1;
int t=match[i];//小孩所喜欢的零食中,查找没被匹配的,以及查找有无可以替换的;
if(t==-1||dfs(t)){
match[i]=u;//第i个零食是小孩u的
return 1;
}
}
}
return 0;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>m;
for(int j=1;j<=m;j++){
cin>>b;
e[i][b]=1;
}
}
ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++){//孩子选零食
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;//走进i;
}
if(ans==n)cout<<"Yes"<<endl;
else cout<<"No"<<endl<<n-ans<<endl;
return 0;
}
D-小蓝的二进制询问_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
我的队友最强大脑!!!;
找到从l到r的二进制数下1的个数
0000000
0000001
0000010
0000011
0000100
0000101
0000110
0000111
0001000
0001001
0001010
0001011
0001100
0001101
0001110
0001111
0010000
通过观察可以发现,从右向左开始,第
第一列隔一行01(2)第二列是0011(4),第三列式000111(6),第四列是00001111(8);
我们要计算 l 到 r 的二进制下1的个数,就用1到 r 的1的个数减去1到 l 的1的个数;
我们只需要将 l r 转换成二进制看看二进制下长度是多少,说明我们循环多少次累加1;
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 998244353
int f(int x){
int sum=0;
int p2=1;
for(;p2<=x;p2*=2){//p2是一个01组合中,0或则1的个数
int j=x/(2*p2);//2*p2,代表是一个周期,j表示x行中有几个周期;
sum+=j*p2;//sum加上这一行中的1的个数等于周期数*周期数中1的个数
int y=x%p2-p2/2;//计算没有在周期上,1的个数,因为0在前边,所以x%p2是剩余的数,p2/2是0的个数;
if(y>0)sum+=y;//如果减掉前面0的个数以后值>0,就说明还有1可以加1
sum%=N;
}
sum+=x-(p2)/2;//若x在16到32之间,x为25,当p2为16时也就是计算完第三列后就退出循环,还剩下最后一列没有将一算进去‘
sum%=N;
return sum;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);
int t;
cin >> t;
while(t--){
int l,r;
cin >> l >> r;
cout << (f(r+1)-f(l)+N)%N<< endl;
}
return 0;
}
/*0000000
0000001
0000010
0000011
0000100
0000101
0000110
0000111
0001000
0001001
0001010
0001011
0001100
0001101
0001110
0001111
0010000*/
TIRED!!!!!
G-旅途的终点_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
二分找到答案就行
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>a(200005);
int n,m,k;
bool check(int x){
int mm=m;
auto p=a;
sort(p.begin()+1,p.begin()+x+1,greater<int>());
for(int i=k+1;i<=x;++i){
}
return 1;
}
signed main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0;
int l=0,r=n;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
l=mid+1;
ans=mid;
}
else r=mid-1;
}
cout<<ans<<endl;
return 0;
}
H-两难抉择_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
很显然乘一个最大值(n)是最好的选择,但是要注意,若n==1或则数组中所有的数都为1,那么加就是最好选择
#include<bits/stdc++.h>
using namespace std;
#define int long long
int minn=0;
signed main(){
int n;
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
int c;
cin>>c;
if(c>minn){
minn=c;
}
ans+=c;
}
if(n==1)ans+=1;
else if(minn==1)ans+=n;
else{
ans-=minn;
ans+=minn*n;
}
cout<<ans<<endl;
return 0;
}
I-除法移位_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
要使得结果最大必须保证a1尽可能的大,则就需要找出最后k个数中最大的那个数,如果没有第一个数大,就不移动,否则,就移动n-最大元素的下标+1步;
#include<bits/stdc++.h>
using namespace std;
#define int long long
int pos=0,maxx=0;
int a[200005];
map<int,int>mp;
signed main(){
int n,t;
cin>>n>>t;
int one;
for(int i=1;i<=n;i++){
cin>>a[i];
}
one=a[1];
for(int i=n;i>=1;i--){
mp.insert(make_pair(a[i],i));
}
if(n>t)sort(a+n-t+1,a+1+n);
else {
sort(a+1,a+1+n);
}
// for(int i=1;i<=n;i++)cout<<a[i]<<' ';
if(one>=a[n])cout<<0<<endl;
else cout<<n-mp[a[n]]+1;
return 0;
}
K-图上计数(Easy)_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
如果n是偶数,那么除以二,一边一半平方后最大,
如果是奇数,那么除以二后,有一堆会多一1,同样此时也是最大的
#include<bits/stdc++.h>
using namespace std;
#define int long long
int pos=0,maxx=0;
int a[200005];
map<int,int>mp;
signed main(){
int n,m;
cin>>n>>m;
if(n%2==0)cout<<(n/2)*(n/2)<<endl;
else cout<<(n/2)*((n/2)+1)<<endl;
return 0;
}