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

A. [202409C]和之大

解法1

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

解法2

考虑贪心。先把第 \(k\) 大值转化为求第 \(2^n - k\) 小。观察到第 \(1\) 小就是只选 \(7^0\) ,第 \(2\) 小就是只选 \(7^1\),第 \(3\) 小就是只选 \(7^0,7^1\) 。以此类推,按照 \(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\)。那就是要求满足 \(pre_j - pre_{i-1} \le s\)\((i,j)\) 的个数。固定 \(pre_j\) 即满足 \(pre_j -s \le pre_{i-1}\) 式子左边是定值,前缀和数组也是单调递增的,二分查找即可。

#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]小信整理数组

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

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

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

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

证明:假设 \(a_i \not = i\) 时不把它们加入到同一个集合中。 那么对这个 \(a_i\) 所在集合排序时 \(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;
}
posted @ 2025-01-13 14:35  vanueber  阅读(40)  评论(0)    收藏  举报