Codeforces Round #592 (Div. 2)


傳送門

A. Pens and Pencils

簽到。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
 
int a, b, c, d, k;
 
void run() {
	cin >> a >> b >> c >> d >> k;
	for(int x = 1; x < k; x++) {
		int y = k - x;
		if(x * c >= a && y * d >= b) {
			cout << x << ' ' << y << '\n';
			return;
		}
	}
	cout << -1 << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    int T; cin >> T;
    while(T--) run();
    return 0;
}

B. Rooms and Staircases

簽到。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1005;
 
int n;
char s[N];
 
void run() {
	cin >> n;
	cin >> (s + 1);
	int left = -1, right;
	for(int i = 1; i <= n; i++) {
		if(s[i] == '1') {
			left = i; break;
		}
	}
	for(int i = n; i >= 1; i--) {
		if(s[i] == '1') {
			right = i; break;
		}
	}
	int ans = 0;
	if(left == -1) {
		ans = n;
	} else {
		ans = max(2 * right, 2 * (n - left + 1));
	}
	cout << ans << '\n';
} 
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    int T; cin >> T;
    while(T--) run();
    return 0;
}

C. The Football Season

題意:
現在共有\(n,n\leq 10^{12}\)場比賽,贏一場比賽獲得\(w\)分,平局獲得\(d\)分,輸了不加分,\(1\leq d<w\leq 10^5\)
現在知道總分\(p,p\leq 10^{17}\),求三元組\((x,y,z)\)滿足:

  • \(x\cdot w+y\cdot d=p\)
  • \(x+y+z=n\)

不存在則輸出\(-1\)

思路:
這不是擴歐模板題嗎?也不是那么模板,還要貪心一下求個最小解,所以就卡了一整場比賽。
因為\(d<w\),那么可以知道\(y< w\),因為當\(y\geq w\)時,\(w\)\(d\)不如\(x=d\)時,\(d\)\(w\)划算。
然后\(w\)的范圍也比較小,所以直接枚舉判斷就是了。

或者這樣思考:反正是求較小解,那么得到解過后,\(y\)會模上\(w\),也就是說自然\(y\)的范圍就比較小了。為什么是\(y\)模,因為\(x\)越多總數量越小~

感覺還是挺巧妙的QAQ,沒有細心分析題目性質以及數據范圍。
所以說模板題不可信!!

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
 
ll n, p, w, d;
 
void run() {
	for(int y = 0; y < w; y++) {
		if(p - y * d < 0) break;
		if((p - y * d) % w == 0) {
			ll x = (p - y * d) / w;
			if(n - x - y >= 0) {
				cout << x << ' ' << y << ' ' << n - x - y << '\n';
				return;
			}
		}
	}
	cout << -1 << '\n';
	return;
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> p >> w >> d) run();
    return 0;
}

D. Paint the Tree

容易發現只有鏈的情況合法,鏈的情況就很簡單了。
因為顏色個數較少,所以直接枚舉顏色排列染色就行。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
 
int n;
int c[3][N];
int a[N], d[N], color[N], tmp[N];
vector <int> g[N];
int T;
 
void dfs(int u, int fa) {
	a[++T] = u;
	for(auto v : g[u]) {
		if(v == fa) continue;
		dfs(v, u);
	}
}
 
void run() {
	for(int i = 1; i <= n; i++) {
		d[i] = 0;
		g[i].clear();
	}
	T = 0;
	for(int i = 0; i < 3; i++) {
		for(int j = 1; j <= n; j++) {
			cin >> c[i][j];
		}
	}
	for(int i = 1; i < n; i++) {
		int u, v; cin >> u >> v;
		++d[u], ++d[v];
		g[u].push_back(v), g[v].push_back(u);
	}
	for(int i = 1; i <= n; i++) {
		if(d[i] >= 3) {
			cout << -1 << '\n';
			return;
		}
	}
	int rt;
	for(int i = 1; i <= n; i++) {
		if(d[i] == 1) rt = i;
	}
	dfs(rt, 0);
	int col[3] = {0, 1, 2};
	ll ans = 1e18;
	do {
		ll res = 0;
		for(int i = 1; i <= n; i++) {
			res += c[col[(i - 1) % 3]][a[i]];
			tmp[a[i]] = col[(i - 1) % 3];
		}
		if(res < ans) {
			ans = res;
			memcpy(color, tmp, sizeof(color));
		}
	} while(next_permutation(col, col + 3));
	cout << ans << '\n';
	for(int i = 1; i <= n; i++) cout << color[i] + 1 << " \n"[i == n];
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n) run();
    return 0;
}

E. Minimizing Difference

題意:
給出\(n\)個數,現在你可以執行不超過\(k\)次操作,每次操作可以讓一個數加一或者減一。
問最后最大與最小值的差值最小是多少。

思路:

  • 顯然差值具有單調性,可以考慮二分差值。
  • 注意到最終最優的情況中,一定存在某個數其沒有發生改變。
  • 那么直接枚舉下界和上界,二分找另外一個界限就行(也可以利用雙指針)。

至於為什么可以一定存在某個數不會改變,可以這樣考慮:
若最終存在至少兩個不同的數,那肯定滿足;
若最終是只有一個值,那么一定會達到只有兩個值的狀態,我們固定一個數量較多的不變就行,不影響結果。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
 
ll n, k;
int a[N];
ll sum[N];
 
bool chk(int d) {
	for(int i = 1; i <= n; i++) {
		int low = lower_bound(a + 1, a + n + 1, a[i]) - a - 1;
		int high = upper_bound(a + 1, a + n + 1, a[i] + d) - a;
		ll tot = 1ll * low * a[i] - sum[low] + sum[n] - sum[high - 1] - 1ll * (n - high + 1) * (a[i] + d);
		if(tot <= k) return true;
	}
	for(int i = 1; i <= n; i++) {
		int high = upper_bound(a + 1, a + n + 1, a[i]) - a;
		int low = lower_bound(a + 1, a + n + 1, a[i] - d) - a - 1;
		ll tot = 1ll * low * (a[i] - d) - sum[low] + sum[n] - sum[high - 1] - 1ll * (n - high + 1) * a[i];
		if(tot <= k) return true;
	}
	return false;
}
 
void run() {
	for(int i = 1; i <= n; i++) cin >> a[i];
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
	int l = 0, r = 1e9 + 1, mid;
	while(l < r) {
		mid = (l + r) >> 1;
		if(chk(mid)) r = mid;
		else l = mid + 1;
	}
	cout << l << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> k) run();
    return 0;
}

F. Chips

題意:
給出一個只有黑白兩種顏色的環,然后執行\(k\)次操作,每次操作,對於每個位置,若其兩邊的顏色和它不同,它的顏色就發生改變。
\(k\)次過后的顏色狀態是什么。
注意一下,每次操作中,顏色改變是同時的。

思路:
關鍵在於連續的段,很容易發現顏色連續的段顏色不會發生改變。
那么我們將所有連續的段提取出來,每次單獨考慮兩個連續段的中間部分,將\(k\)\(len\)\(min\)暴力修改即可。
易知復雜度不超過\(O(n)\)
注意一下因為是環,開頭和結尾的部分不是很好處理,所以可以將序列復制兩次,最后只看中間部分,這樣就比較方便處理。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5;
 
int n, k;
char s[3 * N];
 
struct seg{
	int l, r, c;
}a[N];
 
void run() {
	cin >> (s + 1);
	for(int j = n + 1; j <= 3 * n; j++) {
		s[j] = s[j - n];
	}
	s[3 * n + 1] = '\0';
	int tot = 0;
	for(int i = 1, j; i <= 3 * n; i = j) {
		j = i + 1;
		while(j <= 3 * n && s[i] == s[j]) ++j;
		int col = (s[i] == 'W' ? 0 : 1);
		if(j - i > 1)
			a[++tot] = {i, j - 1, col};
	}
	// for(int i = 1; i <= tot; i++) {
	// 	cout << a[i].l << ' ' << a[i].r << '\n';
	// }
	for(int i = 1; i < tot; i++) {
		int len = a[i + 1].l - 1 - a[i].r;
		if(a[i].c == a[i + 1].c) {
			if(len - 2 * k > 0) {
				for(int j = a[i].r + 1; j <= a[i].r + k; j++) {
					s[j] = (a[i].c == 0 ? 'W' : 'B');
				}
				for(int j = a[i + 1].l - 1; j >= a[i + 1].l - k; j--) {
					s[j] = (a[i].c == 0 ? 'W' : 'B');
				}
				for(int j = a[i].r + k + 1; j <= a[i + 1].l - k - 1; j++) {
					s[j] = (s[j - 1] == 'W' ? 'B' : 'W');
				}
			} else {
				for(int j = a[i].r + 1; j <= a[i + 1].l - 1; j++) {
					s[j] = (a[i].c == 0 ? 'W' : 'B');
				}
			}
		} else {
			if(len - 2 * k > 0) {
				for(int j = a[i].r + 1; j <= a[i].r + k; j++) {
					s[j] = (a[i].c == 0 ? 'W' : 'B');
				}
				for(int j = a[i + 1].l - 1; j >= a[i + 1].l - k; j--) {
					s[j] = (a[i + 1].c == 0 ? 'W' : 'B');
				}
				for(int j = a[i].r + k + 1; j <= a[i + 1].l - k - 1; j++) {
					s[j] = (s[j - 1] == 'W' ? 'B' : 'W');
				}
			} else {
				for(int j = a[i].r + 1; j <= a[i].r + len / 2; j++) {
					s[j] = (a[i].c == 0 ? 'W' : 'B');
				}
				for(int j = a[i + 1].l - 1; j >= a[i + 1].l - len / 2; j--) {
					s[j] = (a[i + 1].c == 0 ? 'W' : 'B');
				}				
			}			
		}
	}
	if(tot == 0 && k & 1) {
		for(int i = n + 1; i <= 2 * n; i++) {
			s[i] = (s[i] == 'W' ? 'B' : 'W');
		}
	}
	for(int i = n + 1; i <= 2 * n; i++) {
		cout << s[i];
	}
	cout << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> k) run();
    return 0;
}

G. Running in Pairs

題意:
給出兩個排列\(p,q\),先可以任意調換排列的順序,求最大的\(\sum_{i=1}^{n}max(p_i,q_i)\),同時其不能超過\(k\)

思路:

  • 觀察可以發現,在所有的\(max(p_i,q_i)\)中,同一個數最多出現兩次。
  • 采用貪心策略,應盡可能接近\(k\),所以每次將目前最大和最小的交換。
  • 若交換過后值超過\(k\),因為交換產生的貢獻是連續的,所以我們選取中間最優的進行交換即可。

這G貌似有點簡單。。。就是一個普通的貪心。。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
// #define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 5;
 
ll n, k;
int a[N], b[N];
 
void run() {
	ll ans = (n + 1) * n / 2;
	if(ans > k) {
		cout << -1 << '\n';
		return;
	}
	for(int i = 1; i <= n; i++) a[i] = b[i] = i;
	int p = n / 2;
	int now = n - 1, pos = 1;
	for(int i = 1; i <= p; i++) {
		if(ans + now > k) {
			swap(a[pos], a[pos + k - ans]);
			break;
		}
		ans += now;
		now -= 2;
		swap(a[pos], a[n - pos + 1]);
		++pos;
	}
	ll sum = 0;
	for(int i = 1; i <= n; i++) sum += max(a[i], b[i]);
	cout << sum << '\n';
	for(int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n];
	for(int i = 1; i <= n; i++) cout << b[i] << " \n"[i == n];
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> k) run();
    return 0;
}


免責聲明!

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



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