2023.7.19 记录

文章分享了作者在刷AtCoder和牛客网编程题目的经验,涉及题目包括团队分配、区间子数组和图着色问题,使用了暴力搜索、状态压缩和并查集等算法,目标是提升基础和思维能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

感觉自己基础不够扎实, 思维不够灵敏,所以最近主要在刷cf和abc的题。

AtCoder Beginner Contest 310 D - Peaceful Teams  

 题目大意:给定n,t,m,n表示有多少个人,t表示队伍个数,m表示敌人关系数量
求:把n个人分为t支队伍有多少个方案数(敌人不能在一个队)
由于数据量太小,直接暴搜。

vector<int>tim;  //存储每一个队伍的代表人物
int ey[15];      //存储每一个人的敌人(ey[i]的二进制上为1的表示是敌人)
int n, t, m;
int ans;

void dfs(int now) {
	if(now > n) {
		ans += (tim.size() == t);
		return;
	}
	
	for(int v : tim) {
		if(!(ey[v] & (1 << (now - 1))) ) {
			int ey1 = ey[v];
			ey[v] |= ey[now];   //敌人累加
			dfs(now + 1);
			ey[v] = ey1;       //回溯
		}
	}
	
	if(tim.size() < t) {  //添加到队伍中
		tim.push_back(now);
		dfs(now + 1);
		tim.pop_back();
	}
}
	
void solve() {
	
	cin >> n >> t >> m;
	
	rep(i, 1, m) {
		int a, b;
		cin >> a >> b;
		ey[a] |= 1 << (b - 1);
		ey[b] |= 1 << (a - 1);
	}
	
    tim.reserve(t);
	dfs(1);
	
	cout << ans << endl;
}
牛客练习赛 112 B qsgg and Subarray

 因为0&什么都是0,不难知道一个区间只要为0,那么所有包含这个区间的值也为0
数据为1e9,所以我们枚举到31位,用lst存每一位为0的最大下标,相当于右端点
最后枚举lst中的最小值设为左端点,这时右端点不动,所有包含该区间的的区间数就为左端点的值
 

const int N = 1e6 + 10;
int a[N], lst[32];
void solve() {
	int n;
	cin >> n;
	rep(i, 1, n) {
		cin >> a[i];
	}
	ll ans = 0;
	rep(i, 1, n) {
		rep(j, 0, 31) {
			if(!((a[i] >> j) & 1)) {
				lst[j] = i;
			}
		}
		int minn = 1e9;
		rep(j, 0, 31) {
			minn = min(minn, lst[j]);
		}
		ans += minn;
	}
	cout << ans << endl;
}
AtCoder Regular Contest 164 B Switching Travel

题目大意:n个顶点,m条边,无向图,每一个顶点都有一种颜色,0为白,1为黑。
可以进行的操作:选一个顶点作为起点出发,可以移动到与自身颜色不同的顶点上,移动后上一个顶点变色(白<->黑)。
问是否可以回到起点。
思路:很自然的想到要回到起点,肯定要有一个环(首尾相连),而且因为每走过一个点,该点就会变色,所以首尾初始时,一定
要是同一个颜色。
做法:用并查集维护连通分量,检查每个连通分量中是否有颜色相同的顶点,若有,则输出Yes,若检查完了之后还没有输出Yes,则
输出No。

const int N = 2e5 + 10;
int pre[N];
int col[N];
struct {
	int u, v;
}g[N];

int find(int f) {
	if(pre[f] == f) return f;
	else return pre[f] = find(pre[f]);
}

void solve() {
	int n, m;
	cin >> n >> m;
	rep(i, 1, m) {
		cin >> g[i].u >> g[i].v;
	}
	rep(i, 1, n) {
		cin >> col[i];
		pre[i] = i;	
	}
	rep(i, 1, m) {
		int u = g[i].u, v = g[i].v;
		if(col[u] != col[v]) {
			pre[find(u)] = pre[find(v)];
		}
	}
	rep(i, 1, m) {
		int u = g[i].u, v = g[i].v;
		if(col[u] == col[v]) {
			if(pre[find(u)] == pre[find(v)]) {
				cout << Yes << endl;
				return;
			}
		}
	}
	cout << No << endl;
}
 AtCoder Regular Contest 164 Reversible Card Game

题目大意:n张双面均有数字的卡片,A先选择一张翻面,B再选一张取出,并获得正面的数字分值。
求B可以获得的最大分值,A要尽量减少B获得的分值。
贪心:A要选取正面和反面差值最大的翻,B也要选择差值最大的拿。
做法:优先队列。

struct node {
	int a, b;
	bool operator < (const node& temp) const {
		return (temp.a - temp.b) > (a - b);
	}
};

void solve() {
	int n;
	cin >> n;
	priority_queue<node>q;
	rep(i, 1, n) {
		int a, b;
		cin >> a >> b;
		q.push({a, b});
	}
	ll ans = 0;
	while(!q.empty()) {
		node p = q.top();
		q.pop();
		q.push({p.b, p.a});
		p = q.top();
		q.pop();
		ans += p.a;
	}
	cout << ans << endl;
}

每天刷一下cf和abc,以及学算法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

akb000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值