Codeforces Round #591


Contest Info


[Practice Link](https://codeforces.com/contest/1240)
Solved A B C D E F
4/6 O O O O - -
  • O 在比賽中通過
  • Ø 賽后通過
  • ! 嘗試了但是失敗了
  • - 沒有嘗試

Solutions


A. Save the Nature

題意:
\(n\)個數\(p_i\)

  • 如果一個下標它是\(a\)的倍數,那么這個位置的價值就是\(a_i \cdot x\%\)
  • 如果一個下標它是\(b\)的倍數,那么這個位置的價值就是\(a_i \cdot y\%\)
  • 如果一個下標它是\(lcm(a, b)\)的倍數,那么這個位置的價值就是\(a_i \cdot (x + y)\%\)

現在可以給\(p_i\)重新排序,問排序最最少多少個前\(y\)個數,使得前\(y\)個數的價值和大於等於\(k\)

思路:
二分答案,然后將大的貪心放在大的位置上。

代碼:

view code
#include <bits/stdc++.h>
#define debug(...) { printf("#  "); printf(__VA_ARGS__); puts(""); }
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }
inline void pt() { cout << endl; }
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); }
template <class T> inline void pt(const T &s) { cout << s << "\n"; }
template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } 
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
constexpr int N = 2e5 + 10;
int n, p[N], x, y, a, b; ll k; 
bool check(ll mid) {
	ll lcm = 1ll * a * b / gcd(a, b);
	ll cnt[3] = {mid / a - mid / lcm, mid / b - mid / lcm, mid / lcm};
	ll tot = 0;
	for (int i = 1; i <= mid; ++i) {
		if (cnt[2]) {
			tot += 1ll * p[i] / 100 * (x + y);
			--cnt[2];
		} else if (cnt[1]) {
			tot += 1ll * p[i] / 100 * y;
			--cnt[1];
		} else if (cnt[0]) {
			tot += 1ll * p[i] / 100 * x;
			--cnt[0];
		} else break;
	}
	return tot >= k;
}
void run() {
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> p[i];
	sort(p + 1, p + 1 + n, [&](int x, int y) { return x > y; }); 
	cin >> x >> a >> y >> b >> k;
	if (x > y) swap(x, y), swap(a, b);
	int l = 1, r = n, res = -1;
	while (r - l >= 0) {
		int mid = (l + r) >> 1;
		if (check(mid)) {
			res = mid;
			r = mid - 1;
		} else 
			l = mid + 1;
	}
	pt(res);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	int _T; cin >> _T;
	while (_T--) run();
	return 0;
}

B. Sequence Sorting

題意:
給出一個序列\(a_i\),每次可以選擇一種數,將這種數全丟到前面或者全丟到后面。
問最少操作幾次,使得該序列變成非降序。

思路:
考慮最多保留多少種數。顯然保留下來的肯定是非降序的數,並且是連續的。
那么直接掃一遍即可。

代碼:

view code
#include <bits/stdc++.h>
#define debug(...) { printf("#  "); printf(__VA_ARGS__); puts(""); }
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }
inline void pt() { cout << endl; }
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); }
template <class T> inline void pt(const T &s) { cout << s << "\n"; }
template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } 
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
constexpr int N = 3e5 + 10;
int n, a[N], l[N], r[N]; 
void run() {
	cin >> n;
	memset(l, 0x3f, sizeof (l[0]) * (n + 10));
	memset(r, 0, sizeof (r[0]) * (n + 10));
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		chmin(l[a[i]], i);
		chmax(r[a[i]], i);
	}
	int res = 1, tot = 0;
	int lst = 0, sum = 0; 
	for (int i = 1; i <= n; ++i) if (r[i] != 0) {
		++tot;
		if (l[i] > lst) {
			lst = r[i];
			++sum;
			chmax(res, sum); 
		} else {
			lst = r[i]; 
			sum = 1;
		}
	}
	pt(tot - res);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	int _T; cin >> _T;
	while (_T--) run();
	return 0;
}

C. Paint the Tree

題意:
給出一棵樹,給每個點塗上\(k\)種顏色,一種顏色最多塗給兩個點,但是有無限種顏色可以塗。
一條邊的價值是如果它兩個端點共有至少一種顏色,那么它的價值為它的權值,否則為\(0\)
現在問整棵樹所有邊的價值和最大是多少,在最優塗色方案下。

思路:
\(f[i][0]\)表示\(i\)的子樹中並且\(i\)沒有一種顏色可以塗的最大價值,\(f[i][1]\)表示\(i\)的子樹中並且\(i\)還剩了至少一種顏色可以塗的最大價值。
那么一個\(u\),它最多選擇\(k\)\(f[v][1] + w\)進行轉移,我們先假設全都選\(f[v][0]\)轉移,然后維護一個堆,里面放的是\(f[v][1] + w - f[v][0]\),貪心選取前\(k\)大即可。

代碼:

view code
#include <bits/stdc++.h>
#define debug(...) { printf("#  "); printf(__VA_ARGS__); puts(""); }
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }
inline void pt() { cout << endl; }
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); }
template <class T> inline void pt(const T &s) { cout << s << "\n"; }
template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } 
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
constexpr int N = 5e5 + 10;
int n, k, fa[N]; ll f[N][2], g[N]; 
vector <vector<pII>> G;
void dfs(int u) {
	f[u][0] = f[u][1] = 0;
	for (auto &it : G[u]) {
		int v = it.fi, w = it.se;
		if (v == fa[u]) continue;
		fa[v] = u;
		dfs(v);
		g[v] = f[v][1] + w - f[v][0];
		f[u][0] += f[v][0]; 
		f[u][1] += f[v][0]; 
	}
	vector <int> id;
	for (auto &it : G[u]) if (it.fi != fa[u]) id.push_back(it.fi);
	sort(id.begin(), id.end(), [&](int x, int y) { return g[x] > g[y]; });
	for (int i = 0, sze = id.size(); i < k && i < sze; ++i) {
		int v = id[i];
		if (g[v] < 0) break;
		if (i < k - 1) f[u][1] += g[v];
		f[u][0] += g[v];
	}
}
void run() {
	cin >> n >> k;
	G.clear(); G.resize(n + 1); 
	for (int i = 1, u, v, w; i < n; ++i) {
		cin >> u >> v >> w;
		G[u].emplace_back(v, w);
		G[v].emplace_back(u, w);
	}
	fa[1] = 1;
	dfs(1);
	pt(max(f[1][0], f[1][1]));
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	int _T; cin >> _T;
	while (_T--) run();
	return 0;
}

D. Stack Exterminable Arrays

題意:
給出\(n\)個數,維護一個棧,將一個數列加到棧中,這么加:

  • 如果棧空或者棧頂不等於當前數\(a_i\),那么將\(a_i\)加入到棧頂
  • 如果棧頂的數等於當前數\(a_i\),那么棧頂彈出。

現在詢問有多少連續子序列操作完后棧是空的。

思路:
我們考慮枚舉每個連續子序列的右端點,統計有多少個左端點滿足。
我們用\(S[i]\)表示前\(i\)個數的操作完后的棧序列。
那么當且僅當\(S[i] = S[j]\)的時候,\([i +1, j]\)這段序列操作完后棧是空的。
\(S[i]\)哈希一下即可。

代碼:

view code
#include <bits/stdc++.h>
#define debug(...) { printf("#  "); printf(__VA_ARGS__); puts(""); }
#define fi first
#define se second
#define endl "\n" 
using namespace std;
using db = double;
using ll = long long;
using ull = unsigned long long; 
using pII = pair <int, int>;
using pLL = pair <ll, ll>;
constexpr int mod = 1e9 + 7;
template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } 
template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; }
template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; }
inline int rd() { int x; cin >> x; return x; }
template <class T> inline void rd(T &x) { cin >> x; }
template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; }
inline void pt() { cout << endl; }
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); }
template <class T> inline void pt(const T &s) { cout << s << "\n"; }
template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } 
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; }
constexpr int N = 3e5 + 10;
//
struct Hash {
	static ull base[N]; 
	static void init() {
		base[0] = 1;
		for (int i = 1; i < N; ++i)
			base[i] = base[i - 1] * 19260817;  
	}
	ull a[N]; 
	inline void work() { a[0] = 0; }
	inline void add(int ch, int id) { 
	    a[id] = a[id - 1] * 19260817 + ch;	
	}
}hs;
ull Hash::base[N] = {0};
map <ull, int> mp;
int n, a[N], sta[N]; 
void run() {
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> a[i];
	mp.clear();
	mp[0] = 1; *sta = 0;
	ll res = 0;
	hs.work();
	for (int i = 1; i <= n; ++i) {
		if (*sta && sta[*sta] == a[i]) --*sta;
		else sta[++*sta] = a[i], hs.add(a[i], *sta);
		ull H = hs.a[*sta]; res += mp[H];
		++mp[H];
	}
	pt(res);
}

int main() {
	Hash::init();
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	int _T; cin >> _T;
	while (_T--) run();
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM