牛客小白月赛30 全题解

最近比赛状态有点迷,这场题目其实都挺简单的.压根没涉及到高级的算法和思维.
A-黑白边
最小生成树裸题.判断一下无解就好了.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int nxt[N],head[N],to[N],edge[N],ct;
void addedge(int x,int y,int z){
    
    
	nxt[++ct] = head[x];head[x] = ct;to[ct] = y;edge[ct] = z;
}
struct E{
    
    
	int x,y,z;
};
bool cmp(E a,E b){
    
    
	return a.z < b.z;
}
vector<E> e;
int fa[N];
int find(int x){
    
    
	int r,j,k;r=j=k=x;
	while(r!=fa[r]) r=fa[r];
	while(j!=r) j=fa[k],fa[k]=r,k=j;
	return r;
}
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
    fir(i,1,n) fa[i] = i;
	fir(i,1,m){
    
    
		int x,y,z;
		cin >> x >> y >> z;
		addedge(x,y,z);
		addedge(y,x,z);
		E ee = {
    
    x,y,z};
		e.pb(ee);
	}
	sort(ALL(e),cmp);
	int num = 0;
	for(auto x:e){
    
    
		int fx = find(x.x),fy = find(x.y);
		if(fx!=fy){
    
    
			num+=x.z;
			fa[fx] = fy;
		}
	}
	int f = 0;
	fir(i,1,n){
    
    
		int fx = find(i);
		if(!f) f = fx;
		else if(f!=fx){
    
    
			f = -1;
			break;
		}
	}
	if(f == -1) cout << -1 << "\n";
	else cout << num << '\n';
	
	return 0;
}	

B-最好的宝石
线段树裸题,比赛的时候因为一个小问题线段树的代码出错了(标注在代码里了),搞的去思路混乱,敲了个带修主席树还炸了空间…迷迷迷.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 3e6+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
namespace seg{
    
    
	int mx[N],num[N];
	#define ls 2*i
	#define rs 2*i+1
	void add(int i,int l,int r,int p,int v){
    
    
		if(l == r){
    
    
			mx[i] = v,num[i] = 1;
			return;
		}
		int mid = l + r >> 1;
		if(p <= mid) add(ls,l,mid,p,v);
		else add(rs,mid+1,r,p,v);
		num[i] = 0;mx[i] = max(mx[ls],mx[rs]);
		if(mx[ls] == mx[i]) num[i] += num[ls];
		if(mx[rs] == mx[i]) num[i] += num[rs];
		return;
	}
	//pii lmx,rmx; // 千万不要把变量设在全局上,因为在询问右半区间的时候会改掉这个值
	// 这个错误以前似乎犯过一次,没想到还会再犯..和这题一血擦肩而过
	pii ask(int i,int l,int r,int L,int R){
    
    
		if(l >= L && r <= R) return mpr(mx[i],num[i]);
		int mid = l + r >> 1;
		if(R <= mid) return ask(ls,l,mid,L,R);
		if(L > mid) return ask(rs,mid+1,r,L,R);
		pii lmx = ask(ls,l,mid,L,mid),rmx = ask(rs,mid+1,r,mid+1,R);
		pii res = mpr(max(lmx.ft,rmx.ft),0);
		if(res.ft == lmx.ft) res.sd+=lmx.sd;
		if(res.ft == rmx.ft) res.sd+=rmx.sd;
		return res;
	}
}
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
	fir(i,1,n){
    
    
		int x;
		cin >> x;
		seg::add(1,1,n,i,x);
	}
	fir(i,1,m){
    
    
		string op;int l,r;
		cin >> op >> l >> r;
		if(op[0] == 'C') seg::add(1,1,n,l,r);
		else cout << seg::ask(1,1,n,l,r).ft << " " << seg::ask(1,1,n,l,r).sd << "\n";
	}
	
	return 0;
}	

C-滑板上楼梯
贪心的先走3再走1就好了.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	LL n;
	cin >> n;
	LL num = n/4;
	n %= 4;
    if(n == 3) cout << num*2+1;
	else cout << num*2+n;
	
	return 0;
}	

D-GCD
唯一 一个和思维沾点边的题.考虑1~n的素数个数为x.那么小于等于x的集合我们都可以找到全是素数的集合作为反例.那么只要输出x+2即可(1也要算上去).
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	int num = 2;
    fir(i,2,n){
    
    
        bool f = 1;
        for(int j = 2;j*j <= i; ++ j){
    
    
            if(i%j==0){
    
    
                f = 0;
                break;
            }
        }
        num += f;
    }
    cout << (num>n?-1:num);
	
	return 0;
}	

E-牛牛的加法
模拟.注意一下扔掉前导零,而且保证ans.size()>=1(0+0 = 0).

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	string a,b;
	cin >> a >> b;
	if(a.size() < b.size()) swap(a,b);
	int lena = a.size(),lenb = b.size();
	string c;
    int j = lenb-1;
	afir(i,lena-1,0){
    
    
		int x=0;
		if(j>=0) x = b[j]-'0',j--;
		x = (x+a[i]-'0')%10;
		c += char(x+'0');
	}
    while(c.size() > 1 && c.back() == '0') c.pop_back();
	reverse(ALL(c));
	cout << c;
	
	return 0;
}	

F-石子合并
一个贪心题,显然每次都取最大的旁边两个之一,这样保证配对的和最大.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int w[N];
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	LL sum = 0;
	int mx=0;
	fir(i,1,n) cin >> w[i],sum += 1LL*w[i],mx=max(mx,w[i]);
	sum -= 1LL*mx;
	cout << sum+1LL*mx*(n-1) << "\n";
	
	return 0;
}	

E-滑板比赛
也是一道经典的贪心.只有一维的限制.每次二分找到第一个大于b[i]的就可以了.具体实现直接用multiset即可.

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int a[N],b[N];
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
	multiset<int> st;
	fir(i,1,n) cin >> a[i],st.insert(a[i]);
	fir(i,1,m) cin >> b[i];
	int num = 0;
	fir(i,1,m){
    
    
		auto v = st.upper_bound(b[i]);
		if(v == st.end()){
    
    
            st.erase(st.begin());
            continue;
        }
        num++;
        st.erase(v);
	}
	cout << num;
	
	return 0;
}	

H-第 k 小
比赛的时候第一反应用平衡树敲.结果T了.其实直接用权值线段树即可.也可以用整体二分.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 1e7+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

namespace seg{
    
    
	int tot,ls[N],rs[N],sum[N];
	void add(int &now,int l,int r,int p,int v){
    
    
		if(!now) now = ++tot;
		int mid = l + r >> 1;
		sum[now]+=v;
		if(l >= r) return;
		if(p <= mid) add(ls[now],l,mid,p,v);
		else add(rs[now],mid+1,r,p,v);
	}
	int ask(int now,int l,int r,int k){
    
    
		if(l == r) return l;
		int mid = l + r >> 1;
		if(sum[ls[now]] >= k) return ask(ls[now],l,mid,k);
		else return ask(rs[now],mid+1,r,k-sum[ls[now]]);
	}
}
using namespace seg;
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m,k,ro=0;
	cin >> n >> m >> k;
	fir(i,1,n){
    
    
		int x;
		cin >> x;
		add(ro,0,1e9,x,1);
	}
	fir(i,1,m){
    
    
		int op,x;
		cin >> op;
		if(op == 1){
    
    
			n++;cin >> x;
			add(ro,0,1e9,x,1);
		}
		else{
    
    
			if(n < k){
    
    
				cout << -1 << "\n";
				continue;
			}
			cout << ask(ro,0,1e9,k) << "\n";
		}
	}
	
	return 0;
}	

I-区间异或
看到n才3000,直接枚举所有的区间,然后二分出第一个>=x的位置.然后就是一个后缀最大值问题.比赛的时候脑袋瓦特了用线段树维护.其实直接扫一遍即可.
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;
const int M = 1e7+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int a[N],ans[M];
pii vec[M];
int cnt;
int main(){
    
    
	int n,m;
	n = read();m = read();
	fir(i,1,n) a[i] = read();
	fir(i,1,n){
    
    
		int sum = 0;
		afir(j,i,1){
    
    
			sum ^= a[j];
			vec[++cnt] = mpr(sum,i-j+1);
		}
	}
    sort(vec+1,vec+1+cnt);
    ans[cnt+1] = INT_MAX;
    afir(i,cnt,1) ans[i] = min(ans[i+1],vec[i].sd);
    fir(i,1,m){
    
    
		int x;
		x = read();
		int pos = lower_bound(vec+1,vec+1+cnt,mpr(x,-1))-vec;
        if(pos == cnt+1) printf("-1\n");
		else printf("%d\n",ans[pos]);
	}
	
	return 0;
}	

J-小游戏
很简单的一道dp,按权值从大到小dp.dp[i]表示选了权值i能达到的max.转移方程dp[i] = max(dp[i+1],dp[i+2]+i*num[i]);
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

LL a[N],dp[N],num[N];
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	fir(i,1,n) cin >> a[i],num[a[i]]++;
	LL ans = 0;
	afir(i,2e5,0){
    
    
		dp[i] = max(dp[i+1],dp[i+2]+num[i]*i);
		ans = max(ans,dp[i]);
	}
	cout << ans;
	
	return 0;
}	

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/110737280