• AtCoder Beginner Contest 249 赛时记录


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

    掉大分

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

    A - Jogging

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

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

    B - Perfect String

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

    C - Just K

    \(n\) 很小,直接 \(2^n\) 枚举,然后 \(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

    发现 \(a_i \le 2 \times 10^5\),果断把 \(a_i\) 扔到值域上统计出现次数。

    然后暴力枚举一下 \(i\)\(i \times j\) 就好了,复杂度是喜闻乐见的调和级数 \(\mathcal O(V \ln V)\)

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

    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 题,随便冲了一发就过了。

    \(f_{i,j}\) 表示填完前 \(i\) 个位置,缩减后长度为 \(j\) 的方案数。

    显然有一个 \(n^3\) 的转移就是:

    \[\begin{aligned} f_{i,len_i} & = 26 \\ f_{i,j} & = 25 \times \sum_{k=1}^{i-1} f_{k,j-len_{i-k}} \end{aligned} \]

    其中 \(len_{i}\) 表示一个长度为 \(i\) 的字符串缩减后的长度。这个可以预处理一下。

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

    我们考虑处理一个前缀和 \(s_{i,j} = \sum_{k=1}^{i} f_{k,j}\)

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

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

    总复杂度是 \(\mathcal O(n^2)\) 的。

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

    #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

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

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

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

    中途如果扫过 \(t_i=1\)\(K<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;
    }
    
  • 相关阅读:
    c语言cgi笔记
    End of script output before headers错误解决方法
    我的树莓派3配置脚本
    Qt学习(4)
    Qt学习(3)
    Qt学习(2)
    Qt学习(1)
    C++ Primer中文版(第五版)——第六章 函数
    C++ 11 ----Lambda表达式
    Java SPI 源码解析
  • 原文地址:https://www.cnblogs.com/Silymtics/p/ABC249.html
Copyright © 2020-2023  润新知