排位賽 12 題解
A - Cards
題意
給出n個數(shù)字,求如何兩兩分組可以讓每組數(shù)字之和相等。
思路
水。暴力。
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int n; scanf("%d", &n);
int num[107]; int sum = 0;
for (int i = 0; i < n; ++i) {
scanf("%d", num+i);
sum += num[i];
}
int par = sum/(n/2);
int vis[107] = {};
for (int i = 0; i < n; ++i) {
if (vis[i]) continue;
for (int j = i+1; j < n; ++j) {
if (vis[j]) continue;
if (num[i] + num[j] == par) {
vis[j] = 1;
printf("%d %d\n", i+1, j+1);
break;
}
}
}
return 0;
}
B - Cells Not Under Attack
題意
在 $n\times n$ 的棋盤上放車,求棋盤上有多少個點不能被這些車攻擊到。
思路
去掉被車覆蓋的行和列即可。
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
#define LL __int64
const int maxn = 1e5+7;
int row[maxn], col[maxn];
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int n, m;
scanf("%d%d", &n, &m);
LL x = n, y = n;
memset(row, 0, sizeof row);
memset(col, 0, sizeof col);
while (m--) {
int a, b; scanf("%d%d", &a, &b);
if (!row[a]) ++row[a], --x;
if (!col[b]) ++col[b], --y;
printf("%I64d ", x*y);
}
return 0;
}
C - They Are Everywhere
題意
給出一個字符串,找出最短的包含所有出現(xiàn)過的字母的子串的長度。
思路
尺取法。用兩個變量作為指針,先移動后面的,再移動前面的,更新每個字符出現(xiàn)的次數(shù)。維護最小值。
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
const int maxn = 1e5+7;
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int n; scanf("%d", &n);
char s[maxn]; scanf("%s", s);
map<char,int> vis;
for (int i = 0; i < n; ++i) vis[s[i]] = 1;
int let_num = vis.size(); vis.clear();
int cnt = 1, l = 0, r = 0;
vis[s[0]] = 1;
int ans = 0x3f3f3f3f;
while (r < n) {
while (cnt < let_num) {
if (++r >= n) break;
if (!vis[s[r]]) ++cnt;
++vis[s[r]];
}
while (cnt >= let_num) {
ans = min(ans, r-l+1);
--vis[s[l]];
if (!vis[s[l++]]) --cnt;
}
}
printf("%d\n", ans);
return 0;
}
D - As Fast As Possible
題意
一群小學(xué)生出門,小學(xué)生走路速度為v1,大巴速度為v2,大巴一次能載人k個,路癡·求n個小學(xué)生走完l長度的路的最短時間。所有人都只能最多坐一次大巴。
思路
最短時間就是最后一個人到達的時間,那么我們要讓所有人坐大巴的時間相同。設(shè)每個人坐大巴的時間為t1,大巴送過一批人之后回頭接到另一批人的間隔時間為t2,將n個人分為p組,我們只要解如下的方程組即可。
$$
\left{
\begin{aligned}
p\cdot t_1+(p-1)t_2 = &t, \
t_1\cdot v_2+(t-t_1)v_1 = &L, \
t_2\cdot v_2+(t_1+t_2)v_1 = &t_1\cdot v_2
\end{aligned}
\right.
$$
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
double n, l, v1, v2, k;
scanf("%lf%lf%lf%lf%lf", &n, &l, &v1, &v2, &k);
int p = (int)n%(int)k?n/k+1:n/k;
double t1 = l*p/(v2-v1) + l*(p-1)/(v2+v1);
double t2 = v1*p/(v2-v1) + v1*(p-1)/(v2+v1) + 1;
printf("%.8lf\n", t1/t2);
return 0;
}
E - The Unique MST
題意
給出一張圖,求最小生成樹是否是唯一的。
思路
次小生成樹模板題。
代碼
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
#define LOCAL
const int inf = 0x3f3f3f3f;
const int maxn = 105;
bool vis[maxn], used[maxn][maxn];
int lowc[maxn], pre[maxn], Max[maxn][maxn];
int prim(int cost[][maxn], int n){
int ans = 0;
memset(Max, 0, sizeof Max);
memset(used, false, sizeof used);
memset(vis, false, sizeof vis);
vis[0] = true;
pre[0] = -1;
for (int i = 1; i < n; ++i){
lowc[i] = cost[0][i];
pre[i] = 0;
}
lowc[0] = 0;
for (int i = 1; i < n; ++i){
int minc = inf;
int p = -1;
for (int j = 0; j < n; ++j) if (!vis[j] && minc > lowc[j]){
minc = lowc[j];
p = j;
}
if (minc == inf) return -1;
ans += minc;
vis[p] = true;
used[p][pre[p]] = used[pre[p]][p] = true;
for (int j = 0; j < n; ++j){
if (vis[j]) Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]);
if (!vis[j] && lowc[j] > cost[p][j]){
lowc[j] = cost[p][j];
pre[j] = p;
}
}
}
return ans;
}
int ans;
int check(int cost[][maxn], int n){
int Min = inf;
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
if (cost[i][j] != inf && !used[i][j])
Min = min(Min, ans + cost[i][j] - Max[i][j]);
if (Min == inf) return -1;
return Min;
}
void solve(){
int cost[maxn][maxn], n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j){
if (i == j) cost[i][j] = 0;
else cost[i][j] = inf;
}
while (m--){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
--x, --y;
cost[x][y] = cost[y][x] = w;
}
ans = prim(cost, n);
if (ans == -1 || ans == check(cost, n)) printf("Not Unique!\n");
else printf("%d\n", ans);
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int t; scanf("%d", &t);
while (t--) solve();
return 0;
}
F - Homer Simpson
題意
有t的時間,有兩種漢堡可以吃,
第一種花費m的時間,第二種花費n,
要求盡量使得所有時間都被利用起來。
思路
完全背包問題。
代碼
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define LOCAL
const int maxn = 1e5+7;
const int inf = 0x3f3f3f3f;
int dp[maxn];
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int m, n, t;
while (~scanf("%d%d%d", &m, &n, &t)) {
for (int i = 1; i <= t; ++i) dp[i] = -inf;
dp[0] = 0;
for (int i = m; i <= t; ++i)
dp[i] = max(dp[i], dp[i-m]+1);
for (int i = n; i <= t; ++i)
dp[i] = max(dp[i], dp[i-n]+1);
int ans = t;
while (dp[ans] < 0) --ans;
printf("%d", dp[ans]);
ans == t? puts("") : printf(" %d\n", t-ans);
}
return 0;
}
G - Pasha and Stick
題意
有一根長為t的木條,求有多少種方法能將其切成非正方形的矩形。
思路
水。注意點是要判斷0。
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int n; scanf("%d", &n);
int half = n/2;
if (n&1)
puts("0");
else if (half&1)
printf("%d", half/2);
else
printf("%d %d", (half-1)/2, half/2-1);
return 0;
}
H - Vika and Squares
題意
有n種涂料,給出每種涂料的數(shù)量。用涂料涂色時,若x用第i種涂料,則x+1用第i+1種涂料。問最多能連續(xù)涂多少塊。
思路
模擬。先找出最多能循環(huán)涂多少次,然后找出最長的一個字段,和首尾比較,得到結(jié)果。注意答案需要用__int64。
代碼
#include <bits/stdc++.h>
using namespace std;
#define LOCAL
#define LL __int64
const int maxn = 2e5+7;
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int n; scanf("%d", &n);
int num[maxn], mi;
for (int i = 1; i <= n; ++i) {
scanf("%d", num+i);
mi = min(mi, num[i]);
}
LL ans = 0;
ans += 1LL*mi*n;
int flag = 0, t = 0;
// flag -> 子串長度
// t -> 最大子串長度
for (int i = 1; i <= n; ++i) {
num[i] -= mi;
if (!num[i]) {
if (flag) t = max(t, flag);
flag = 0;
}
else ++flag;
}
if (flag) t = max(t, flag);
int ht = 0, i = 1; // head & tail
while(num[i] && i <= n) ++i, ++ht;
i = n;
while(num[i] && i > 0) --i, ++ht;
t = max(t, ht);
printf("%d\n", ans + t);
return 0;
}