2024.3.6 训练记录(10)

文章讨论了解决CF竞赛中涉及的三个问题:图论中的代价优化问题,使用优先队列策略;容斥原理的应用;以及二进制数据结构在字符串操作中的应用。
摘要由CSDN通过智能技术生成

CF 1935C Messenger in MAC

题目链接

第一想法是转换成图论,每往后选一个点相当于走一条边,边的代价就是这个新点对于总体的代价贡献,然后跑最短路这样

但是是不行的!!!因为答案要求的是点的数量尽可能多,代价只需要满足条件就可以了,并不需要最小化代价,类似于这种不需要最小化代价的问题,都不可以转化成最短路来做!

理解能力有限(但我坚持认为是题目描述太抽象了!!!),没能考虑到应该最小化后半部分绝对值的大小,只要b是从大到小排序的,绝对值的部分就不需要付出多余的代价,因此按照b排序,每次枚举选的第一个点和最后一个点,看中间可以选哪些数(利用优先队列,优先选a值小的数,也就是,一旦代价超过题目限制,就优先删除大的数),每次更新答案即可

#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;

const int N = 200010;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, l;
    cin >> n >> l;
    vector<PII> a(n);
    for (int i = 0; i < n; i ++ ) cin >> a[i].second >> a[i].first;
	sort(a.begin(), a.end());
	int ans = 0;
	for (int i = 0; i < n; i ++ )
	{
		priority_queue<int> q;
		int tmp = 0, cnt = 0;
		for (int j = i; j < n; j ++ )
		{
			tmp += a[j].second;
			cnt ++ ;
			q.push(a[j].second);
			while (tmp + a[j].first - a[i].first > l && q.size())
			{
				tmp -= q.top();
				cnt -- ;
				q.pop();
			}
			if (tmp + a[j].first - a[i].first > l) break;
			ans = max(ans, cnt);
		}
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 1935D Exam in MAC

题目链接

很普的容斥,但是本人又把题看错了,xy是0-c内所有数都可以选,不是只能选集合里的数

总共能选 (c + 1) * (c + 2) / 2 组,枚举每个数分别作为x+y和y-x,每次减去 x+y 在集合里的组合 k / 2 + 1,减去 y-x 在集合里的组合 c - x + 1 ,加上 x+y 和 y-x 都在集合里的组合,这个怎么计算呢,假设 x + y = a, y - x = b,a 和 b 都在集合中,那么 x = (a - b) / 2 y = (a + b) / 2,我们发现只要 ab 的奇偶性相同就有解,循环中每次把当前的数当做 a ,记录前方(包括自己,因为xy可以相等)有多少和自己奇偶性相同的数,每次加上这个值即可

#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;

const int N = 200010;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, c;
	cin >> n >> c;
	int cnt[2] = {0, 0};
	int ans = (c + 1) * (c + 2) / 2;
	for (int i = 0; i < n; i ++ )
	{
		int x; cin >> x;
		ans -= x / 2 + 1;
		ans -= c - x + 1;
		cnt[x & 1] ++ ;
		ans += cnt[x & 1];
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 706D Vasiliy’s Multiset

题目链接

第一次遇到二进制+字典树结合的题目,可以记录一下

把每个数的二进制存到字典树里,按题目进行操作就可以

#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;

const int N = 200010 * 32;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int nxt[N][2], idx;
int cnt[N]; // 该结点结尾的字符串是否存在

void insert(string s, int l) // 插入字符串,l是字符串长度
{ 
	int p = 0;
	for (int i = 0; i < l; i++)
	{
		cnt[p] ++ ;
		int c = s[i] - '0';
		if (!nxt[p][c]) nxt[p][c] = ++ idx; // 如果没有,就添加结点
		p = nxt[p][c];
	}
	cnt[p] ++ ;
}

int find(string s, int l, int x) // 查找字符串,l是字符串长度
{
	int p = 0;
	for (int i = 0; i < l; i++)
	{
		int c = s[i] - '0';
		if (!nxt[p][c ^ 1] || cnt[nxt[p][c ^ 1]] == 0)
		{
			if (c == 1) x -= (1 << (29 - i));
			p = nxt[p][c];
		}
		else
		{
			if (c == 0) x += (1 << (29 - i));
			p = nxt[p][c ^ 1];
		}
	}
	return x;
}

void drop(string s, int l) // 删除字符串,l是字符串长度
{
	int p = 0;
	for (int i = 0; i < l; i++)
	{
		cnt[p] -- ;
		int c = s[i] - '0';
		if (!nxt[p][c]) return;
		p = nxt[p][c];
	}
	cnt[p] -- ;
}

void solve()
{
	string tt = "";
	for (int i = 0; i < 30; i ++ ) tt += "0";
	insert(tt, tt.size());
	int q;
	cin >> q;
	while (q -- )
	{
		char ch;
		int x, tmp;
		cin >> ch >> x;
		tmp = x;
		string s = "";
		while (tmp)
		{
			if (tmp & 1) s += "1";
			else s += "0";
			tmp >>= 1;
		}
		while (s.size() < 30) s += "0";
		reverse(s.begin(), s.end());
		if (ch == '+') insert(s, s.size());
		else if (ch == '-') drop(s, s.size());
		else if (ch == '?')
		{
			int tmp = find(s, s.size(), x);
			cout << tmp << '\n';
		}
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 580D Diane

题目链接

昨晚写了没保存,懒得打字了单纯记录一下就这样吧

#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;

const int N = 200010 * 32;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	cin >> n;
	if (n == 1) cout << "a\n";
	else if (n == 2) cout << "ab\n";
	else if (n == 3) cout << "abc\n";
	else
	{
		string s1(n / 2, 'a'), s2(n / 2 - 1, 'a');
		if (n - n / 2 - (n / 2 - 1) == 2) s1 = s1 + "bc" + s2;
		else s1 = s1 + "b" + s2;
		cout << s1 << '\n';
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t -- )
	{
		solve();
	}
}
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Texcavator

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

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

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

打赏作者

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

抵扣说明:

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

余额充值