3.24~3.30

牛客周赛86

A

签到

#include <bits/stdc++.h>
using namespace std;

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int x,y;
	cin >> x >> y;
	cout << (y%x ? y/x+1 : y/x) << '\n';
	return 0; 
}

B

贪心,很明显删除全部负数就可以使总和最大,也就是把正数相加

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e5+1;

signed main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n,k;
		cin >> n >> k;
		int sum =0,cache;
		for(int i=0;i<n;i++){
			cin >> cache;
			if(cache > 0)
				sum += cache;
		}
		cout << sum << '\n';
	}
	return 0; 
}

C

自己写几个例子就会发现:

两个相邻的数相同,删删删

删到最后一定是0101或1010这种相邻不相同的,那么操作次数就是这种串的长度整除2

用栈/队列等都可实现

#include <bits/stdc++.h>
using namespace std;

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n;
		string str;
		cin >> n >> str;
		stack <char> s;
		for(auto c:str){
			if(!s.empty() && s.top() == c)
				s.pop();
			else s.push(c);
		}
		cout << s.size() / 2 << '\n';
	}
	return 0;
}

D

构造。可以发现,操作次数最多为三,因为如果不能一次过,那么第一次和第二次构造两个相同的数,第三次进行^,一定为0

操作次数为1的情况:

x == y或者 x&y == 0

操作次数为2的情况:

令对x和y做四种操作之一后,结果为a

a == xora == yora&x == 0ora&y == 0

其余的就是操作次数为3

#include <bits/stdc++.h>
using namespace std;

void solve(int x,int y){
	if(x == y || (x&y)==0){
		cout << "1\n";
		return;
	}
	int a = x&y, b = x|y, c = x^y, d = __gcd(x,y);
	if((a&y)==0 || (a&x)==0 || a==y || a==x || (b&y)==0 || (b&x)==0 || b==y || b==x || (c&y)==0 || (c&x)==0 || c==y || c==x || (d&y)==0 || (d&x)==0 || d==y || d==x){
		cout << "2\n";
		return;
	}
	cout << "3\n";
	return;
}

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int x,y;
		cin >> x >> y;
		solve(x,y);
	}
	return 0;
}

背包练习

想找dp练练,但是找的第一题是个裸背包,后面不裸

(此题可忽略!)以下是第一题

#include <bits/stdc++.h>
using namespace std;
int c[101],w[101],dp[101][1001];

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t,m;
	cin >> t >> m;
	for(int i=1;i<=m;i++)
		cin >> c[i] >> w[i];
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=m;i++){
		for(int j=1;j<=t;j++){
			if(j>=c[i]) dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
			else dp[i][j] = dp[i-1][j];
		}
	}
	cout << dp[m][t] << '\n';
	return 0;
}

第二题

有点难度的,并查集+dp,还要优化,不然要MLE(亲身体验过)

如上,方法就是并查集+dp

但是n最大时1e4,常规背包就是1e8,大概100MB,会MLE,所以用滚动数组优化

并查集也有优化,每次合并都需要矮树合并到高树,否则祖先就不对

路径压缩也要单独拎出来写,不能像原来一样揉到find_s里,因为不只是tree[i]的祖先要更新,相应的价钱和价值也要一起更新

调试比较多

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+1;

int tree[maxn],high[maxn]={0},c[maxn],w[maxn],dp[maxn];
int true_c[maxn]={0},true_w[maxn]={0};

void __init__(){
	for(int i=1;i<=maxn;i++)
		tree[i] = i;
}

int find_s(int x){
	return (x==tree[x] ? x : find_s(tree[x]));
}

void union_s(int a,int b){
	int x = find_s(a);
	int y = find_s(b);
	if(x == y) return;
	if(high[x] == high[y]){
		high[x] += 1;
		c[tree[x]] += c[tree[y]];
		w[tree[x]] += w[tree[y]];
		tree[y] = x;
	}
	else{
		if(high[x] < high[y]){
			c[tree[y]] += c[tree[x]];
			w[tree[y]] += w[tree[x]];
			tree[x] = y;
		}
		else{
			c[tree[x]] += c[tree[y]];
			w[tree[x]] += w[tree[y]];
			tree[y] = x;
		}
	}
	/*if(x!=y){
		tree[x] = tree[y];
		c[tree[x]] += c[tree[y]];
		w[tree[x]] += w[tree[y]];
	}*/
}

void update(int n){
	for(int i=1;i<=n;i++){
		int root = find_s(i);
		if(tree[i] != root){
			c[root] += c[tree[i]];
			w[root] += w[tree[i]];
			tree[i] = root;
		}
	}
}

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	__init__();
	memset(dp,0,sizeof(dp));
	int n,m,money;
	cin >> n >> m >> money;
	for(int i=1;i<=n;i++)
		cin >> c[i] >> w[i];
	for(int i=1;i<=m;i++){
		int u,v;
		cin >> u >> v;
		union_s(u,v);
	}
	for(int i=1;i<=n;i++){
		if(!true_c[tree[i]])
			true_c[tree[i]] = c[tree[i]];
		if(!true_w[tree[i]])
			true_w[tree[i]] = w[tree[i]];
	}
	update(n);
	for(int i=1;i<=n;i++){
		for(int j=money;j>=c[i];j--){
			dp[j] = max(dp[j],dp[j-true_c[i]]+true_w[i]);
		}
	}
	//for(int i=1;i<=n;i++){
	//	cout << tree[i] << '\n';
	//}
	//for(int i=1;i<=money;i++)
	//	cout << dp[i] << '\n';
	//for(int i=1;i<=n;i++){
	//	cout << true_w[i] << ' ';
	//}
	cout << dp[money] << '\n';
	return 0;
}
posted @ 2025-06-14 12:25  HLAIA  阅读(5)  评论(0)    收藏  举报