AtCoder Beginner Contest 249 赛时记录

赛时只切了 4 题,2022 开年来的第一次,输麻了/ll

掉大分

安慰一下自己,常在河边走,哪有不掉分~

A - Jogging

直接按照题目要求的模拟一下,看看谁的得分高就可以。

tnnd 题面一开始错了,WA 了一发,比着题面和样例看了半天才看出来/px

B - Perfect String

随便拿个桶记录下就好了。

C - Just K

n 很小,直接 2n 枚举,然后 O(26n) 求一下价值,对价值取个 max 就好了。

signed main() {
	int n = read(), K = read();
	for(int i = 1; i <= n; ++i) {
		cin >> s + 1;
		int len = strlen(s + 1);
		for(int j = 1; j <= len; ++j) {
			cnt[i][s[j] - 'a'] ++;
		}
	}
	int Max = 0;
	for(int S = 0; S < (1 << n); ++S) {
		int ans = 0;
		for(int i = 0; i < 26; ++i) {
			int res = 0;
			for(int j = 1; j <= n; ++j) {
				if(!((S >> j - 1) & 1)) continue;
				res += cnt[j][i];
			}
			if(res == K) ans ++;
		}
//		cout << S << " " << ans << "\n";
		Max = max(Max, ans);
	}
	cout << Max << "\n";
    return 0;
}

D - Index Trio

发现 ai2×105,果断把 ai 扔到值域上统计出现次数。

然后暴力枚举一下 ii×j 就好了,复杂度是喜闻乐见的调和级数 O(VlnV)

注意我们并不需要考虑去重的问题。

signed main() {
	n = read();
	for(int i = 1; i <= n; ++i) cnt[read()] ++;
	int M = 200000;
	for(int i = 1; i <= M; ++i) 
		for(int j = i; j <= M; j += i) 
			ans += cnt[i] * cnt[j] * cnt[j / i];
	cout << ans << "\n";
	return 0;
}

E - RLE

重新看了一下 E 题,随便冲了一发就过了。

fi,j 表示填完前 i 个位置,缩减后长度为 j 的方案数。

显然有一个 n3 的转移就是:

fi,leni=26fi,j=25×k=1i1fk,jlenik

其中 leni 表示一个长度为 i 的字符串缩减后的长度。这个可以预处理一下。

因为 leni 的值只有四种取值(2,3,4,5),而转移的时候这些又是连续的。

我们考虑处理一个前缀和 si,j=k=1ifk,j

那么转移后面的求和部分可以利用这个前缀和快速算出。

我们只需要暴力写一下四种取值的转移即可。

总复杂度是 O(n2) 的。

下面是代码,代码去掉了不重要的部分。

#define int long long
const int MAXN = 3e3 + 100;
const int INF = 1e9 + 7;

int n, mod, ans = 0;
int f[MAXN][MAXN]; // f[i][j] 表示前 i 个位置,长度为 j 的方案数
int sum[MAXN][MAXN]; // sum[i][j] = \sum_{k=1}^{i} f[k][j]
int len[MAXN];

int Mod(int x) {
	if(x < 0) return (x % mod + mod) % mod;
	return x % mod;
}
int Get(int i, int j, int L, int R) {
	if(j - len[L] < 0) return 0;
	return Mod(sum[max(0ll, i - L)][j - len[L]] - sum[max(0ll, i - R)][j - len[L]]) * 25 % mod;
}

signed main() {
	n = read(), mod = read();
	for(int i = 1; i < 10; ++i) len[i] = 2;
	for(int i = 10; i < 100; ++i) len[i] = 3;
	for(int i = 100; i < 1000; ++i) len[i] = 4;
	for(int i = 1000; i <= 3000; ++i) len[i] = 5;
	f[0][0] = 1;
	for(int i = 1; i <= n; ++i) {
		f[i][len[i]] = 26;
		for(int j = 1; j <= n; ++j) {
			f[i][j] = Mod(f[i][j] + Get(i, j, 1, 10));
			f[i][j] = Mod(f[i][j] + Get(i, j, 10, 100));
			f[i][j] = Mod(f[i][j] + Get(i, j, 100, 1000));
			f[i][j] = Mod(f[i][j] + Get(i, j, 1000, 3001));
			sum[i][j] = Mod(sum[i - 1][j] + f[i][j]);
		}
	}
	for(int j = 1; j < n; ++j) ans = Mod(ans + f[n][j]);
	cout << ans << "\n";
	return 0;
}

F - Ignore Operations

因为还没调出来,先口胡一下做法。 调出来了,思路没有问题。

就是倒着枚举,遇到 ti=1 的时候,看一下从这里到最后获得的价值最大是多少,对答案去一个 max。过去之后要用一次跳来消除这个位置的影响。

动态维护一个 sum,每遇到一个 ti=2,如果 y20,那么可以不用跳。否则的话,把它扔进一个堆里,如果堆里的元素个数 >K,取出最小的加进 sum 中。

中途如果扫过 ti=1K<0,那么可以直接 break 掉。

最后直接输出答案即可。

#define int long long
const int MAXN = 4e5 + 10;
const int INF = 1e18 + 7;
const int mod = 998244353;

int n, K, ans = - INF, sum = 0;
int a[MAXN], b[MAXN];
priority_queue<int, vector<int>, less<int> > Q;

signed main() {
	n = read(), K = read();
	for(int i = 1; i <= n; ++i) a[i] = read(), b[i] = read();
	ans = 0; int Cnt = 0;
	for(int i = 1; i <= n; ++i) {
		if(a[i] == 1) ans = b[i];
		else ans += b[i], ++Cnt;
	}
	a[0] = 1, b[0] = 0;
	for(int i = n; i >= 0; --i) {
		if(a[i] == 1) {
			ans = max(ans, b[i] + sum);
			--K;
			if(K < 0) break;
		} else {
			if(b[i] >= 0) sum += b[i];
			else Q.push(b[i]);
		}
		while(!Q.empty() && Q.size() > K) {
			sum += Q.top(), Q.pop();
		}
	}
	cout << ans << "\n";	
	return 0;
}
posted @   Suzt_ilymtics  阅读(206)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示