A. X Axis
题目大意
给x轴上三点,要求找出一点到三点的距离和最小。
思路
三点中间点即是满足条件最优点。
代码实现
void solve(){
vector<ll>o(3);
for (int i = 0; i < 3; i++)cin >> o[i];
sort(o.begin(), o.end());
cout << abs(o[1] - o[0]) + abs(o[1] - o[2]) << "\n";
}
B. Matrix Stabilization
题目大意
给定一矩阵,要求让矩阵上每个点都不满足严格大于周围的点,每次只能让一个值减一,求最终矩阵什么样要求最少操作。
思路
判即可。
让不满足的变成周围四个点中最大得的即可。
代码实现
ll dt[210][210];
void solve(){
ll n, m; cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> dt[i][j];
}
}
ll fx[4][2] = { {0,1},{1,0},{-1,0},{0,-1} };
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
ll sum = 0;
ll be = 4;
for (int ii = 0; ii < 4; ii++) {
ll xx = fx[ii][0] + i;
ll yy = fx[ii][1] + j;
if (xx<1 || xx>n || yy<1 || yy> m) {
be--;
continue;
}
if (dt[xx][yy] < dt[i][j])sum++;
}
if (be == sum) {
ll mx = -1e12;
for (int ii = 0; ii < 4; ii++) {
ll xx = fx[ii][0] + i;
ll yy = fx[ii][1] + j;
if (xx<1 || xx>n || yy<1 || yy> m) {
continue;
}
mx = max(dt[xx][yy], mx);
}
dt[i][j] = mx;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << dt[i][j] << " \n"[j == m];
}
}
}
C. Update Queries
题目大意
给定一个长度为n的字符串,然后给你一个可以任意排序的操作序列,再给一组可以任意排序的字符序列,要求进行完操作的字符串字典序最小。
思路
我们对操作和字符序列进行从小到大排序,对于同一位置的操作,我们可以让他一开始对应较大字典序的字符,然后最后一次用字典序最小的字符。
代码实现
void solve() {
ll n, m; cin >> n >> m;
string s; cin >> s;
vector<ll>o(m);
for (int i = 0; i < m; i++) {
cin >> o[i];
}
sort(o.begin(), o.end());
string b; cin >> b;
sort(b.begin(), b.end());
deque<char>p;
for (auto c : b)p.push_back(c);
queue<char>todo;
for (int i = 0; i < m - 1; i++) {
if (o[i + 1] == o[i]) {
todo.push(p.back());
p.pop_back();
}
else {
todo.push(p.front());
p.pop_front();
}
}
todo.push(p.front()); p.pop_front();
for (int i = 0; i < m; i++) {
char c = todo.front(); todo.pop();
s[o[i] - 1] = c;
}
cout << s << "\n";
}
D. Mathematical Problem
题目大意
给定一个数字字串,要求加入n-2个加或乘在序列里面,求最小值。
思路
对应n=2的字串,直接输出即可。
对于字符串中存在0的,我们只需要判断0两侧可以都可以加乘号,即可直接输出最小值。
1两边如果可以加的话,让他加乘号最优,初次之外都加加号最优。
对于其他情况,我们让每两个成一组,硬判即可。
代码实现
ll o[210000];
ll num(ll l, ll r) {
ll sum = 0;
for (int i = l; i <= r; i++) {
sum += o[i];
if (i != r)sum *= 10;
}
return sum;
}
void solve() {
ll n; cin >> n;
bool flag = false;
for (int i = 1; i <= n; i++) {
char c; cin >> c;
o[i] = c - '0';
if (o[i] == 0 && ((n == 2 || (n == 3 && i == 2))==false))flag = true;
}
if (flag) {
cout << "0\n"; return;
}
if (n == 2) {
cout << num(1, 2) << "\n"; return;
}
ll ans = 1e18;
for (int i = 1; i < n; i++) {
ll sum = 0;
bool flag = 0;
for (int j = 1; j <= n; j++) {
ll now = o[j];
if (j == i) {
j++; now *= 10; now += o[j];
}
if (now == 1) {
flag = true;
}
else {
sum += now;
}
}
if (sum == 0 && flag) {
sum = 1;
}
ans = min(ans, sum);
}
cout << ans << "\n";
}
F. Non-academic Problem
题目大意
给定一个无向图,要求减去图中一个边,使可以互相到达的顶点数量最小。
思路
tarjan求割边板子题。
无向图中,减去一个桥,才可以让答案变化。
我们只需要在判断减下每个桥之后答案的最小值即可。
代码实现
ll n, m;
ll low[MAXN], dfn[MAXN], dfs_clock;
bool isbridge[MAXN];
vector<ll> G[MAXN];
ll cnt_bridge;
ll father[MAXN], siz[MAXN];
ll ans = LLONG_MAX;
void tarjan(int u, int fa) {
father[u] = fa;
low[u] = dfn[u] = ++dfs_clock;
siz[u] = 1;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
siz[u] += siz[v];
if (low[v] > dfn[u]) {
isbridge[v] = true;
ans = min(ans, siz[v] * (siz[v] - 1) / 2 + (n - siz[v]) * (n - siz[v] - 1) / 2);
++cnt_bridge;
}
}
else if (dfn[v] < dfn[u] && v != fa) {
low[u] = min(low[u], dfn[v]);
}
}
}
void solve() {
cin >> n >> m;
dfs_clock = 0; cnt_bridge = 0;
ans = LLONG_MAX;
for (int i = 1; i <= n; i++) {
father[i] = 0; low[i] = 0; dfn[i] = 0;
G[i].clear(); isbridge[i] = false;
siz[i] = 0;
}
for (int i = 1; i <= m; i++) {
ll x, y; cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
tarjan(1, 0);
if (ans == LLONG_MAX) {
cout << n * (n - 1) / 2 << "\n";
return;
}
cout << ans << "\n";
}