Always keep a b|

vanueber

园龄:2年6个月粉丝:0关注:2

信友队2024年9月月赛(普及组)总结

A. [202409C]和之大

解法1

n 很小,所以爆搜就能过。

解法2

考虑贪心。先把第 k 大值转化为求第 2nk 小。观察到第 1 小就是只选 70 ,第 2 小就是只选 71,第 3 小就是只选 70,71 。以此类推,按照 k 的二进制表示下的 1 所在位置就能取到第 k 小了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <ctime>
#include <random>
#include <bitset>
#define int long long

using namespace std;

const int INF = 0x3f3f3f3f;

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

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

const int maxn = 50;
int n, k;
int val[maxn];
bitset<50> now, ed;

signed main()
{
	freopen("202409C.in", "r", stdin);
	freopen("202409C.out", "w", stdout);
	cin >> n >> k;
	val[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		val[i] = val[i - 1] * 7;
//		cout<<val[i]<<endl;
	}
	now = (1 << n) - k;
//	cout<<now<<endl;
	int ans = 0;
	for (int i = 0; i < now.size(); i++)
	{
		if (now[i] == 1) ans += val[i + 1];
	}
	cout << ans << endl;
#ifdef LOCAL
	fprintf(stderr, "%f\n", 1.0 * clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}

B. [202409D] 平衡系统

50pts

直接暴力枚举左右端点 l,r ,加一个前缀和

100pts

先建立一个前缀和数组 pre。那就是要求满足 prejprei1s(i,j) 的个数。固定 prej 即满足 prejsprei1 式子左边是定值,前缀和数组也是单调递增的,二分查找即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <ctime>
#include <random>
#define int long long

using namespace std;

const int INF = 0x3f3f3f3f;

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

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

const int maxn = 1e6 + 5;
int n, s, a[maxn], pre[maxn];
int ans = 0;

signed main()
{
	freopen("202409D.in", "r", stdin);
	freopen("202409D.out","w",stdout);
	n = read(), s = read();
	for (int i = 1; i <= n; i++)
	{
		a[i] = read();
		pre[i] = pre[i - 1] + a[i];
//		cout << pre[i] << " ";
	}
//	puts("");
	for (int i = 1; i <= n; i++)
	{
		int tar = pre[i] - s;
		int x = lower_bound(pre, pre + i + 1, tar) - pre + 1;
//		cout << i << " " << x << " " <<  tar << endl;
		ans += i - x + 1;
	}
	cout << ans << endl;
	return 0;
}

C. [202409E]小信整理数组

赛时智障了,把字序列看成子串导致爆炸了。

解法很简单,因为最后是一个单调递增的序列,它就是一个 1n 的排列。

考虑如何划分才能使还原成一个排列:

如果数字 aii 不同,说明这个数要加入到一个序列中,使它最后还原到原位置,这里将他们合并到到同一个集合中,对每个元素都做这样的操作,最后统计连通块即可。

证明:假设 aii 时不把它们加入到同一个集合中。 那么对这个 ai 所在集合排序时 i 就不能回到 i 这个位置上。证毕。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 2e5 + 5;
int a[maxn], fa[maxn], n, ans;

void init(int n)
{
	for (int i = 1; i <= n; i++) fa[i] = i;
}
int find(int x)
{
	if (fa[x] == x) return fa[x];
	return fa[x] = find(fa[x]);
}
void join(int s1, int s2)
{
	int pa = find(s1), pb = find(s2);
	if (pa != pb) fa[pb] = pa;
}

int main()
{
	freopen("202409E.in","r",stdin);
    freopen("202409E.out","w",stdout);
	cin >> n;
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	init(n);
	for (int i = 1; i <= n; i++)
	{
		join(i, a[i]);
	}
	for (int i = 1; i <= n; i++) if (fa[i] == i) ans++;
	cout << ans << endl;
	return 0;
}

D. [202409F]校园成绩之谜

脑抽 ++。

现将操作离线下来。开一个长度为 k 的窗口,统计每个数的出现次数,再将次数加入集合中取最大,元素出了窗口就删了即可。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;

void solve()
{
	int n, k, q;
	cin >> n >> k >> q;
	vector<int> a(n + 1), ans(n + 1);
	for (int i = 1; i <= n; i++) cin >> a[i];
	map<int, int> cnt;
	multiset<int> s;
	for (int i = 1; i <= n; i++) s.insert(0);

	for (int i = 1; i <= k; i++)
	{
		s.erase(s.find(cnt[a[i]]));
		cnt[a[i]]++;
		s.insert(cnt[a[i]]);
		ans[i] = *s.rbegin();
	}

	for (int i = k + 1; i <= n; i++)
	{
		s.erase(s.find(cnt[a[i - k]]));
		cnt[a[i - k]]--;
		s.insert(cnt[a[i - k]]);

		s.erase(s.find(cnt[a[i]]));
		cnt[a[i]]++;
		s.insert(cnt[a[i]]);

		ans[i] = *s.rbegin();
	}
	// for(int i = 1; i <= n; i++) cout << ans[i] << " "; cout << endl;
	while (q--)
	{
		int x;
		cin >> x;
		cout << ans[x] << endl;
	}
}

int main()
{
	freopen("202409F.in", "r", stdin);
	freopen("202409F.out", "w", stdout);
	int T = 1;
	while (T--)
		solve();
	return 0;
}

本文作者:vanueber

本文链接:https://www.cnblogs.com/vanueber/p/18668592

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   vanueber  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起