Codeforces Round 957 (Div 3)(A—G題解)

_yimg發表於2024-07-13

Codeforces Round 957 (Div. 3)

2024-07-12 —yimg

A

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	vector<int> a(3);
	for(int i = 0; i < 3; ++i) cin >> a[i];
	int t = 5;
	while(t--){
		sort(a.begin(), a.end());
		a[0]++;
	}
	cout << a[0]*a[1]*a[2] << '\n';
}
int main()
{
	int t;
	cin >> t;
	while(t--)
		work();
}

B

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n, k;
	cin >> n >> k;
	vector<int> a(k);
	for(auto &i: a) cin >> i;
	sort(a.begin(), a.end());
	int ans = 0;
	for(int i = 0; i < k - 1; ++i){
		ans += a[i] - 1;
	}
	cout << ans + n - a[k - 1] << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

C

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n, m, k;
	cin >> n >> m >> k;
	vector<int> a(n + 1);
	int j = 1;
	for(int i = n; i > m; --i, ++j){
		a[j] = i;
	}
	for(int i = 1; i <= m; ++i, ++j){
		a[j] = i;
	}
	for(int i = 1; i <= n; ++i)
		cout << a[i] << " ";
	cout << "\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

D

題意:

ErnKor過河,這條河有n個格子,L代表平臺可以跳往[L,L + m]的任意位置,W代表水,每經過一格水要消耗一個體力,最開始有k個體力,也就是最多經過k格水,C代表鱷魚,不能待在C所在的格子。給定n,m,k 和一個代表河流的字串,問能否到達對岸

\(1\le m\le10,0\le k \le 2*10^{5},1\le n \le2*10^{5}\)

思路:

  • 比較容易想到的是用貪心來做,如果在能跳往下一個平臺,跳往下一個平臺一定是最優操作,如果不能,跳滿m格是最優操作,其中會判NO的情況是在水中遇到’C’或者體力不夠用,複雜組O(n + k)

  • dp來解決問題也很淺顯,我們記錄到當前格子要消耗的最小體力,我們當前的格子可能是由前面的格子跳過來的,或者由上一個水游過來的。 鱷魚初始為極大值後不用管,因為我們不能透過‘C’轉移。複雜度為O(nm)。

    \[dp_i = \left\{ \begin{array}{rcl} dp_j & & 0\le i - j \le m, s_j='L'\\ dp_{i-1} + 1 & &s_{i-1}='W'\\ \end{array} \right. \]

程式碼:

貪心
#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n, m, k;
	cin >> n >> m >> k;
	string s;
	cin >> s;
	for(int l = -1, r = 0; r <= s.length(); ++r){
		if(l == s.length()) break;
		if(l + m < r){
			l = l + m;
			if(s[l] == 'C'){
				cout << "NO\n";
				return;
			}
			while(1){
				k--;
				++l;
				if(s[l] == 'C' || k < 0){
					cout << "NO\n";
					return;
				}
				if(l == s.length() || s[l] == 'L'){
					r = l;
					break;
				}
			}
		}
		else if(r == s.length() || s[r] == 'L'){
				if(l + m >= r){
					l = r;
				}
			}
		
	}
	cout << "YES\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}
DP
#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n, m, k;
	cin >> n >> m >> k;
	string s;
	cin >> s;
	s = "L" + s + "L";
	vector<int> f(n + 5, 1e9 + 7);
	f[0] = 0;
	for(int i = 1; i <= n + 1; ++i){
		
		for(int j = 1; j <= m; ++j){
			if(i - j >= 0 && s[i - j] == 'L')
				f[i] = min(f[i], f[i - j]);
		}
		if(s[i - 1] == 'W') f[i] = min(f[i], f[i - 1] + 1);
	}
	if(f[n + 1] <= k) cout << "YES\n";
	else cout << "NO\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

E

題意:

給定n, 問有多少對符合要求的數對(a, b)滿足 \(n*a-b=f(n, a, b)\)

定義\(f(n,a,b)\)為將n個a順序拼在一起,刪去後b位剩下的數

\(1\le a \le10^4, 1\le b \le min(10^4,n*a)\)

思路:

a和b的範圍都很小,直接列舉a,對於此a我們限制b的範圍,\(b = a*len(n)-len(f)\) , 對每個a我們列舉\(b\in[a*len(n)-1,a*len(n)-5]\) 驗證答案。

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n;
	cin >> n;
	string chn = to_string(n);
	string s;
	int ln = chn.length();
	for(int i = 1; i <= 10; ++i) s += chn;
	vector<pair<int, int>> ans;
	const int N = 1e4;
	for(int a = 1; a <= N; ++a){
		for(int b = max(a*ln-5, 1); b <= min(a*ln-1, min(N, a*n)); ++b){
			int num = 0;
			for(int i = 0; i < ln*a-b; ++i) num = num * 10 + s[i] - '0';
			if(n*a-b == num) ans.push_back({a,b});
		}
	}
	cout << ans.size() << '\n';
	for(auto v : ans)
		cout << v.first << " " << v.second << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

F

題意:

一個段\((l,r)\) 如果不存在索引 \(i_1 < i_2 < \ldots < i_k\)\(l \le i_1, i_k \le r\) 使得 \(a_{i_1} \cdot a_{i_2} \ldots \cdot a_{i_k} = x\)

則稱這個段為壞段,每個元素屬於且只屬於一個段,且分段後,所有的段都是壞段,問壞段的最小數量

思路:

貪心地分段,如果一個元素可以分到上一個段就把它放到上一個段,否則分一個新段。

實現上,可以維護使當前段乘積為x的元素(也就是因子),要避免重複可以用set,複雜度為O(nlog(D(x)))

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n, x;
	cin >> n >> x;
	vector<int> a(n + 1);
	for(int i = 1; i <= n; ++i) cin >> a[i];
	set<int> s;
	vector<int> tmp;
	int ans = 1;
	s.insert(x);
	for(int i = 1; i <= n; ++i){
		if(a[i] == 1) continue;	
		tmp.clear();
		for(auto el : s) {
			if(el%a[i] == 0)
				tmp.push_back(el/a[i]);
		}	
		for(auto el : tmp) s.insert(el);
		if(s.find(1) != s.end()){
			ans++;
			s.clear();
			s.insert(x);
			s.insert(x/a[i]);
		}
	}
	cout << ans << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

G

題意:

\(MEOW(a)\)的值,\(MEOW(a)\)\(MEX(b,|b|+1)\) 的和,b為a的所有不同子集

a為長度為n的陣列{1,2,3,…, n}

\(MEX(S,k)\) 為不包含S中元素的第k大的正整數

思路:

當我們選k個數為子集時:

  • \(2*k+1>n\) 時,MEX值固定為\(2k+1\) ,子集有 \(C_n^k\)
  • \(2*k+1\le n\) 時,MEX值不固定,但是我們可以列舉MEX值,令MEX值為m,我們要算出m-1個數有多少種選法
    • 選比m小的數要從\([1,m-1]\) 中選\(m-1-k\)個, 有\(C_{m-1}^{m-1-k}\)
    • 選比m大的數要從\([m+1,n]\) 中選\(2k+1-m\) 個, 有\(C_{n-m}^{2k+1-m}\)

複雜度為\(O(n^2)\)

實現上,求組合數時要用到乘法逆元,預處理好即可

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5000;
const int mod = 1e9 + 7;
ll fac[N + 5], inv[N + 5];
void init()
{
	fac[0] = fac[1] = 1;
	for(int i = 1; i <= N; ++i)
		fac[i] = fac[i - 1] * i % mod;
	auto qpow = [&](ll base, ll p){
		ll res = 1;
		while(p){
			if(p&1) res *= base, res %= mod; 
			base *= base; base %= mod;
			p >>= 1;
		}
		return res;
	};
	inv[N] = qpow(fac[N], mod - 2);
	for(int i = N - 1; i >= 0; --i)
		inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll C(int a, int b){
	if(a < 0 || b < 0 || a - b < 0) return 0;
	return fac[a] * inv[b] % mod * inv[a-b] % mod;
}
void work()
{
	int n;
	cin >> n;
	ll ans = 1;
	for(int k = 1; k <= n; ++k){
		if(2*k+1 > n){
			ans += (2*k+1) * C(n, k) % mod;
			ans %= mod;
			continue;
		}
		for(int m = k + 1; m <= 2 * k + 1; ++m){
			ans += m * C(m-1, m-1-k) % mod * C(n-m, 2*k+1-m) % mod;
			ans %= mod;
		}
	}
	cout << ans << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	init();
	while(t--)
		work();
}

相關文章