比赛链接:

https://codeforces.com/gym/104090

A. Modulo Ruins the Legend

题意:

给定一个序列 \(a\),让序列加上一个等差序列,求出总和 % \(m\) 的最小值以及等差序列的 \(s\) 和公差 \(d\)

思路:

定义 \(\sum_{i = 1}^n a_i\)\(sum\)
求解的答案为 \((sum + n * s + \frac{n * (n + 1)}{2} * d) \% m\) 的最小值。
根据裴蜀定理得到原式等于 \(sum + x * gcd(n, \frac{n * (n + 1)}{2})\)
加上一个 \(y * m\) 不影响结果(因为对 \(m\) 取模),\(sum + x * gcd(n, \frac{n * (n + 1)}{2}) + y * m\)
再裴蜀,\(sum + k * g\)
求该值的最小,这个值大于 0,所以最小应该是等于 \(m\),得到 \(k = \lceil \frac{sum - m}{g} \rceil\)
通过扩展欧几里得求解值。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
LL exgcd(LL a, LL b, LL &x, LL &y){
	if (!b){
		x = 1, y = 0;
		return a;
	}
	LL d = exgcd(b, a % b, y, x);
	y -= ( a / b ) * x;
	return d;
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL n, m;
	cin >> n >> m;
	LL sum = 0;
	for (int i = 0; i < n; i ++ ){
		int x;
		cin >> x;
		sum = (sum + x) % m;
	}
	
	LL s, d, x, y;
	LL g = exgcd(exgcd(n, n * (n + 1) / 2, s, d), m, x, y);
	LL k = (m - sum + g - 1) / g;
	cout << k * g + sum - m << "\n";
	x = x * k % m;
	cout << (s * x % m + m) % m << " " << (d * x % m + m) % m << "\n";
	return 0;
}

C. No Bug No Game

题意:

\(n\) 件装备,第 \(i\) 件装备负重为 \(p\),人物初始的负重为 0。
如果当前负重为 \(x\),当 \(x + p_i \leq k\),可获得 w_{i, p_i} 的奖励值。当 \(x + p_i > k\),获得 \(w_{i, k - p_i}\) 的奖励值,问最多能获得多少奖励值。

思路:

当装备总负重 \(\leq k\),答案为 \(\sum_{i = 1}^n w_{i, p_i}\)
否则,可以发现,除了一件装备,其它选择的装备获得的奖励值都会是 \(w_{i, p_i}\)
因此可以设 \(f_{i, j, 0}\)\(i\) 件装备,负重为 \(j\),没有选择超过负重的装备的最大奖励值,1 则表示有选择。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, k;
	cin >> n >> k;
	
	const int inf = 1e9;
	vector<vector<array<int, 2>>> f(n + 10, vector<array<int, 2>>(k + 10, {-inf, -inf}));
	int tot = 0, sum = 0;
	f[0][0] = {0, 0};
	
	for (int i = 1; i <= n; i ++ ){
		int p;
		cin >> p;
		tot += p;
		vector<int> w(p + 1);
		for (int j = 1; j <= p; j ++ ){
			cin >> w[j];
		}
		sum += w[p];
		
		for (int j = 0; j <= k; j ++ ){
			f[i][j] = f[i - 1][j];
			if (j >= p){
				f[i][j][0] = max(f[i][j][0], f[i - 1][j - p][0] + w[p]);
				f[i][j][1] = max(f[i][j][1], f[i - 1][j - p][1] + w[p]);
			}
			
			for (int t = 1; t < p; t ++ ){
				if (j >= t){
					f[i][j][1] = max(f[i][j][1], f[i - 1][j - t][0] + w[t]);
				}
			}
		}
	}
	if (tot <= k){
		cout << sum << "\n";
		return 0;
	}
	cout << max(f[n][k][0], f[n][k][1]) << "\n";
	return 0;
}

D. Money Game

题意:

\(n\) 个人玩游戏,第 \(i\) 个人的存款为 \(a_i\),每一轮第一个人将自己一半的存款给第二个人,然后第二个人将自己一半的存款给第三个人...,第 \(n\) 个人将自己一半的存款给第一个人,问无限轮之后每个人手上的存款有多少。

思路:

暴力跑一定轮次可找出规律。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cout << fixed << setprecision(10);
	int n;
	cin >> n;
	double sum = 0;
	for (int i = 0; i < n; i ++ ){
		int x;
		cin >> x;
		sum += x;
	}
	sum /= n + 1;
	for (int i = 0; i < n; i ++ ){
		if (i) cout << sum;
		else cout << sum * 2;
		cout << " \n"[i == n - 1];
	}
	return 0;
}

F. Da Mi Lao Shi Ai Kan De

题意:

\(n\) 个小组,第 \(i\) 个小组有 \(m_i\) 个字符串,输出其中包含 "bie" 的字符串,如果该小组没有,输出 "Time to play Genshin Impact, Teacher Rice!"。

思路:

按题意模拟。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n;
	cin >> n;
	map<string, int> cnt;
	for (int i = 0; i < n; i ++ ){
		int m;
		cin >> m;
		bool ok = false;
		for (int j = 0; j < m; j ++ ){
			string s;
			cin >> s;
			if (s.find("bie") != -1 && !cnt.count(s)){
				cnt[s] = 1;
				cout << s << "\n";
				ok = true;
			}
		}
		if (!ok){
			cout << "Time to play Genshin Impact, Teacher Rice!\n";
		}
	}
	return 0;
}

K. Master of Both

题意:

给定 \(n\) 个字符串,\(q\) 次询问,每次给定 26 个字母的字典序大小,问字符串中有几个逆序对。

思路:

判断两个字符串是不是逆序的,去掉它们的公共前缀,比较大小,因此,是否是逆序由字符串中第一个不同的字符决定。
定义 \(f_{a, b}\)\(n\) 个字符串中只有当 \(a > b\) 时,逆序对的数量。
字符串第 \(i\) 位为 \(u\),下一位为 \(v\)\(f_{j, v}\) 可以加上所有对应 \(v\) 的位置为 \(j\) 的字符串。
统计字符串数量以及计算 \(f\) 数组可以通过 \(Trie\)
为了处理 \(ab\)\(abc\) 这种某个字符串为另一个前缀的情况,加入一个新的字符 'a' - 1,它小于 26 个字母。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1e6 + 10;
LL f[27][27];
int ch[N][27], cnt[N * 30], idx = 0;
void insert(string s){
	int u = 0;
	for (int i = 0; i < s.size(); i ++ ){
		int v = s[i] - 'a' + 1;
		if (!ch[u][v]) ch[u][v] = ++ idx;
		for (int j = 0; j < 27; j ++ ){
			if (j == v) continue;
			f[j][v] += cnt[ch[u][j]];
		}
		u = ch[u][v];
		cnt[u] ++ ;
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, q;
	cin >> n >> q;
	for (int i = 0; i < n; i ++ ){
		string s;
		cin >> s;
		s = s + char('a' - 1);
		insert(s);
	}
	
	while (q -- ){
		string s;
		cin >> s;
		s = char('a' - 1) + s;
		
		LL ans = 0;
		for (int i = 1; i < 27; i ++ ){
			for (int j = 0; j < i; j ++ ){
				ans += f[s[i] - 'a' + 1][s[j] - 'a' + 1];
			}
		}
		cout << ans << "\n";
	}
	return 0;
}
posted on 2023-03-16 21:41  Hamine  阅读(189)  评论(0编辑  收藏  举报