Codeforces Round 958 (Div 2)(A—D題解)

_yimg發表於2024-07-17

Codeforces Round 958 (Div. 2)

2024-07-17 —yimg

A

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n, k;
	cin >> n >> k;
	cout << (n - 1 + k - 2) / (k - 1) << '\n';
} 
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

B

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n; string s;
	cin >> n >> s;
	int c1 = 0, c0 = 0;
	for(int i = 0; i < n; ++i){
		if(s[i] == '1') c1++;
		else if(s[i] == '0' && (i && s[i - 1] != '0' || !i) ) c0++;
	}
	cout << (c1 > c0 ? "YES" : "NO") << '\n';
} 
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

C

題意:

給定正整數n, 求最長序列a,a需要滿足

  • \(a_i\le n\)\(1\le i\le k\).

  • \(a_i>a_{i-1}\)\(2\le i\le k\).

  • \(a_i\,|\,a_{i-1}=n\)\(2\le i\le k\)

思路:

首先根據相鄰兩位按位or為n,我們可以忽略對構造答案沒有影響的0位, 接下來對\(2^{num(1)}-1\) 進行操作,\(a_k\)一定為\(2^{num(1)}-1\) , 貪心的想 : \(a_{k-1}\) 為小於\(a_k\) 的符合要求的最大值 , 即\(2^{num(1)}-1-2^0\) ,我們可以據此構造出num(1) + 1個答案。

實現上,依次刪去最高位就能得到答案。

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	ll n;
	cin >> n;
	vector<int> p;
	ll a = 0, pre = 0;
	for(ll i = 0, tmp = n; tmp; tmp >>= 1, ++i){
		if(tmp&1){
			a++;
			p.push_back(i);
		}
	}
	if(a == 1) cout << 1 << "\n";
	else cout << a + 1 << '\n';
	for(ll i = a - 1; a > 1 && i >= 0; --i){
		ll res = n - (1ll << p[i]);
		cout << res << " ";
	}
	cout << n;
	cout << '\n';
} 
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();

D

題意:

有一顆n個節點的數,每個節點上都有一個攻擊力為\(a_i\)怪物,怪物每回合開始時結算一次攻擊,每個回合中可以進行操作,消滅任意只指定怪物,但是不能消滅相鄰兩個節點的怪物,問受到的攻擊值之和最小為多少。

思路:

選擇在第k回合消滅攻擊力為\(a_i\) 的怪物需要受到攻擊\(ka_i\) , 衝突的情況只有相鄰節點有影響,考慮用動態規劃解決。對於整個問題,回合數最多為\(\lceil log(n) \rceil\) (這個上限不知道怎麼證明)。

\(f_{u,i}\) 為以u為根節點的子樹,選擇回合i時的最小值。記錄子節點的最小值和次小值,進行狀態轉移即可。複雜度為\(O(nlog_n)\)

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n;
	cin >> n;
	vector<ll> a(n + 1);
	vector<vector<ll>> g(n + 1);
	for(int i = 1; i <= n; ++i)
		cin >> a[i];
	for(int i = 1; i < n; ++i){
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	int lgn = __lg(n) + 1;
	vector<vector<ll>> f(n + 1, vector<ll>(lgn + 1));
	auto dfs = [&](auto &&self, int u, int p) -> void{
		for(int i = 1; i <= lgn; ++i)
			f[u][i] = a[u] * i;
		for(auto v : g[u]){
			if(v == p) continue;
			self(self, v, u);
			ll minn = 1e18, lm = 1e18, id = 0;
			for(int i = 1; i <= lgn; ++i){
				if(f[v][i] < lm){
					lm = f[v][i];
					if(lm < minn){
						id = i;
						swap(lm, minn);
					}
				}
			}
			for(int i = 1; i <= lgn; ++i){
				if(i == id) f[u][i] += lm;
				else f[u][i] += minn; 
			}
		}
	};
	dfs(dfs, 1, -1);
	ll minn = 1e18;
	for(int i = 1; i <= lgn; ++i) minn = min(minn, f[1][i]);
	cout << minn << "\n";
} 
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

相關文章