Codeforces Round #592 (Div. 2)

Contest Info


[Practice Link](https://codeforces.com/contest/1244)
Solved A B C D E F G
7/7 O O Ø Ø Ø Ø Ø
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Pens and Pencils

签到。

B. Rooms and Staircases

签到。

C. The Football Season

题意:
给出(n, p, w, d),求解:

[egin{eqnarray*} x cdot w + y cdot d = p \ x + y leq n end{eqnarray*} ]

题目保证(d < w)

思路:
题目保证了(d < w),那么有(y < w),因为如果(y = w),那么相当于(w * d),然后取了(w)(d),那么不如取(d)(w)更优。
所以直接暴力即可。
也可以直接上(exgcd),但是要讨论的东西挺多的。

代码:

view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "
" 
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; }  
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "33[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); }
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; }
//head
constexpr int N = 1e5 + 10;
ll n, p, w, d, x, y; 
void run() {
	for (ll y = 0; y <= w; ++y) {
		if ((p - y * d) % w == 0) {
			x = (p - y * d) / w;
			if (x >= 0 && y >= 0 && x + y <= n) return pt(x, y, n - x - y);
		}
	}
	pt(-1);
}

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

exgcd代码:

view code
import math


def gcd(a, b):
    if b == 0:
        return a
    else:
        return gcd(b, a % b)


def exgcd(a, b, X, Y):
    if a == 0 and b == 0:
        return -1
    if b == 0:
        X[0] = 1
        Y[0] = 0
        return a
    d = exgcd(b, a % b, Y, X)
    Y[0] = Y[0] - a // b * X[0]
    return d

def fceil(x, y):
    return (x + y - 1) // y

def main():
    n, p, w, d = map(int, input().split());
    x = [0]
    y = [0]
    G = gcd(w, d)
    if p % G != 0:
        print(-1)
        return
    if p % w == 0:
        x[0] = p // w
        if x[0] <= n:
            print(x[0], 0, n - x[0])
            return
    if p % d == 0:
        y[0] = p // d
        if y[0] <= n:
            print(0, y[0], n - y[0])
            return
    exgcd(w, d, x, y)
    x[0] = x[0] * p // G
    y[0] = y[0] * p // G
    if x[0] < 0:
        t = fceil(abs(x[0]), d)
        x[0] = x[0] + d * t
        y[0] = y[0] - w * t
    if y[0] < 0:
        t = fceil(abs(y[0]), w)
        x[0] = x[0] - d * t
        y[0] = y[0] + w * t
    if x[0] < 0 or y[0] < 0:
        print(-1)
        return
    t = y[0] // w
    x[0] = x[0] + d * t
    y[0] = y[0] - w * t
    if x[0] + y[0] > n:
        print(-1)
        return
    z = n - x[0] - y[0]
    print(x[0], y[0], z)


main()

D. Paint the Tree

题意:
给出(n)个点的树,有三种颜色,要给每个点染色,给出你每个点染某种颜色的代价。
染色方案要满足不存在任意一个三元组((x, y, z))使得(x, y)有边相连,(y, z)有边相连,并且(x, y, z)有任意两个颜色相同。
求合法方案的最小代价。

思路:
考虑只有一条链的时候才存在方案,并且考虑在链上的话,前两个点的颜色确定了,那么整条链的颜色都确定了。
直接暴力枚举然后判断即可。

代码:

view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "
" 
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; }  
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "33[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); }
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; }
//head
constexpr int N = 1e5 + 10;
int n, d[N], rt, col[N]; ll c[3][N], res, tot; 
vector <vector<int>> G;
void dfs(int u, int fa) {
	for (auto &v : G[u]) if (v != fa) {
		col[v] = 3 - col[u] - col[fa];
		dfs(v, u);
	}
}
ll fee() {
	ll res = 0;
	for (int i = 1; i <= n; ++i)
		res += c[col[i]][i];
	return res;
}
bool ok() {
	for (int i = 1; i <= n; ++i) {
		if (d[i] == 1) rt = i;
		if (d[i] > 2) return false;
	}
	return true;
}
void run() {
	for (int i = 0; i < 3; ++i)
		for (int j = 1; j <= n; ++j)
			cin >> c[i][j];
	memset(d, 0, sizeof d);
	G.clear(); G.resize(n + 1);
	for (int i = 1, u, v; i < n; ++i) {
		cin >> u >> v;
		++d[u]; ++d[v];
		G[u].push_back(v);
		G[v].push_back(u);
	}
	if (!ok()) return pt(-1);
	int a = 0, b = 0; res = 1e18;
	for (int i = 0; i < 3; ++i) {
		for (int j = 0; j < 3; ++j) {
			if (i != j) {
				col[rt] = i;
				col[G[rt][0]] = j;
				dfs(G[rt][0], rt);
				tot = fee(); 
				if (tot < res) {
					res = tot;
					a = i, b = j;
				}
			}
		}
	}
	col[rt] = a; col[G[rt][0]] = b;
	dfs(G[rt][0], rt);
	pt(res);
	for (int i = 1; i <= n; ++i)
		cout << col[i] + 1 << " 
"[i == n];
}

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

思路二:
考虑(f[i][j][k])表示当前点为(i),前一个点的颜色为(j),当前点颜色为(k)的最小花费,然后转移即可。
但是输出方案要维护一个前驱或者直接确定了最后两个暴力推上去。
但是不能通过判断(dp)值来找前驱,这样可能导致染色方案不合法,但是(dp)值可能是相同的

E. Minimizing Difference

题意:
给出(n)个数(a_i),每次可以对一个数增加(1)或者减少(1)。问操作次数不小于(k)的情况下,(n)个数中的最大值减最小值的差值最小是多少

思路:
二分答案,然后考虑合法方案一定能让最大值或者最小值固定在某个(a_i),然后枚举(a_i),算右界范围内的花费是否小于等于(k)即可。

代码:

view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "
" 
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; }  
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "33[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); }
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; }
//head
constexpr int N = 1e5 + 10;
int n; ll a[N], S[N], k; 
ll get(int l, int r) {
	if (l > r) return 0;
	return S[r] - S[l - 1];
}
ll fee(int l, int r) {
	return a[l] * l - get(1, l) + get(r, n) - a[r] * (n - r + 1);
}

bool check(ll x) {
	ll tot = 1e18;
	int pos = 1;
	for (int i = 1; i <= n; ++i) {
		if (pos < i) pos = i;
		while (pos <= n && a[i] + x >= a[pos]) ++pos;
		ll now = a[i] * i - get(1, i) + get(pos, n) - (a[i] + x) * (n - pos + 1);
		chmin(tot, now);
	}
	pos = n;
	for (int i = n; i >= 1; --i) {
		if (pos > n) pos = i;
		while (pos >= 1 && a[i] - x <= a[pos]) --pos;
		ll now = get(i, n) - a[i] * (n - i + 1) - get(1, pos) + (a[i] - x) * pos;
		chmin(tot, now);
	}
	return tot <= k;
}

void run() {
	for (int i = 1; i <= n; ++i) cin >> a[i];
	sort(a + 1, a + 1 + n);
	for (int i = 1; i <= n; ++i) S[i] = S[i - 1] + a[i];
	ll l = 0, r = a[n] - a[1], res = r;
	while (r - l >= 0) {
		ll 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);
	while (cin >> n >> k) run();
	return 0;
}

F. Chips

题意:
给出一个环,每个点有黑白两色,然后有(k)操作,每次操作是这样的:
如果一个点两边的颜色有一个和自己相同,那么这个点的颜色不变,否则这个点的颜色翻转,黑变白,白变黑。
(k)次操作后每个点的颜色。

思路:
考虑先标记所有不动的点。
那么每一段连续的未被标记的点每经过一次操作这一段都会慢慢缩小。直接模拟即可。
把序列复制一遍会比较好写。

代码:

view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "
" 
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; }  
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "33[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); }
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; }
//head
constexpr int N = 4e5 + 10;
int n, k, vis[N]; char s[N]; 
bool ok() {
	for (int i = 2; s[i]; ++i)
		if (s[i - 1] == s[i])
			return false;
	return true;
}
bool ok2() {
	for (int i = 2; s[i]; ++i)
		if (s[i - 1] != s[i])
			return false;
	return true;
}
void gao(int l, int r) {
	if (l == r) {
		s[l] = s[l - 1];
		return;
	}
	char chl = s[l - 1], chr = s[r + 1];
	for (int i = 1; i <= k && l <= r; ++i) {
		s[l] = chl; s[r] = chr;
		++l; --r;
	}
	if (l <= r && (k & 1)) {
		for (int i = l; i <= r; ++i) {
			s[i] = (s[i] == 'W' ? 'B' : 'W'); 
		}
	} 
}
void run() {
	cin >> (s + 1);
	for (int i = n + 1; i <= 2 * n; ++i) s[i] = s[i - n];
	if (ok()) {
		if (k & 1) {
			for (int i = 1; i <= n; ++i) 
				s[i] = (s[i] == 'W' ? 'B' : 'W');
		}
		s[n + 1] = 0;
		return pt(s + 1);
	}
   	if (ok2()) {
		s[n + 1] = 0;
		return pt(s + 1);
	}
	memset(vis, 0, sizeof vis);	
	for (int i = 2; i <= n * 2; ++i) {
		if (s[i - 1] == s[i]) {
			vis[i - 1] = vis[i] = 1;
		}
	}
	if (s[1] == s[n]) {
		vis[1] = vis[n] = vis[n + 1] = vis[n * 2] = 1;
	}
	int pos = 0;
	for (int i = 1; i <= n; ++i) {
		if (vis[i]) {
			pos = i;
			break;
		}
	}
	for (int i = pos + 1, l = -1, r = -1; i <= n + pos; ++i) {
		if (vis[i] == 0) {
			if (l == -1) l = i;
			r = i;
		} else {
			if (l != -1) gao(l, r);
			l = r = -1;
		}
	}
	for (int i = n + 1; i <= n + pos - 1; ++i) cout << s[i];
	for (int i = pos; i <= n; ++i) cout << s[i];
	pt();
}

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

G. Running in Pairs

题意:
要求构造两个排列(p, q),使得(sum = sumlimits_{i = 1}^n max(p_i, q_i) leq k),并且结果最大。

思路:
考虑将第一个排列顺序排放。
然后考虑第二个排列刚开始也是顺序排放的。
然后考虑交换位置视为元素左移和元素右移。
显然,元素右移不会对答案产生影响。
但是元素左移,左移几个位置它就产生多少贡献。
那么显然可以发现这个变化是连续的,直接贪心即可。

代码:

view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl "
" 
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; }  
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0) 
void err() { cout << "33[39;0m" << endl; } 
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A> 
void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); }
inline void pt() { cout << endl; } 
template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); }
template <template<typename...> class T, typename t, typename... A> 
void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); }
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; }
//head
constexpr int N = 1e6 + 10;
int n, a[N]; ll k; 
void run() {
	ll base = 1ll * n * (n + 1) / 2;
	if (base > k) return pt(-1);
	for (int i = 1; i <= n; ++i) a[i] = i;
	ll remind = k - 1ll * n * (n + 1) / 2;
	int low = 1;
	for (int i = n; i >= 1 && i > low; --i) {
		if (i - low <= remind) {
			remind -= i - low;
			swap(a[i], a[low]);
			++low;
		} else {
			swap(a[i], a[i - remind]);
			remind = 0;
			break;
		}
	}
	pt(k - remind);
	for (int i = 1; i <= n; ++i) cout << i << " 
"[i == n];
	for (int i = 1; i <= n; ++i) cout << a[i] << " 
"[i == n];
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	cout << fixed << setprecision(20);
	while (cin >> n >> k) run();
	return 0;
}
原文地址:https://www.cnblogs.com/Dup4/p/11669587.html