10.05模拟赛总结

比赛传送门

总结

\(100+60+0+0=160\),挂了 \(0+40+0+0=40\),Rank 16,寄寄寄寄寄。

T1 优秀 \(\texttt{/}\) \(\texttt{Good}\)

题意

\(l\)\(r\) 之间的 \(2\) 的整数次幂。

分析

解法 1

由于 \(l\)\(r\) 非常小,所以可以直接模拟,没啥好说的。

时间复杂度 \(O(r)\)

解法 2

充分发扬人类智慧,发现肯定只有 \(2^{\left \lceil \log_2 l \right \rceil}\)\(2^{\lfloor \log_2 r \rfloor}\) 这些数,循环输出就行了。

时间复杂度 \(O(\log_2 r)\)

寄因

没寄。

\(\color{red}\text{不要忘记输出 cnt!!!}\)

\(\color{red}\text{不然……}\)

\(\color{red}{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \,\!↑}\)

\(\color{red}{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \!}没有输出\ cnt\ 的皮卡丘\)

代码

自己写吧,这么简单。

解法 1

#include <bits/stdc++.h>

using namespace std;

int l, r;
vector<int> a;

int main() {
  cin >> l >> r;
  int logl = log2(l);
  for (int i = 1 << logl; i <= r; i <<= 1) {
    if (i >= l) {
      a.push_back(i);
    }
  }
  cout << a.size() << '\n';
  for (int i = 0; i < a.size(); i++) {
    cout << a[i] << ' ';
  }
  return 0;
}

解法 2

#include <bits/stdc++.h>

using namespace std;

int l, r;
vector<int> a;

int main() {
  cin >> l >> r;
  int logl = ceil(log2(l)), logr = floor(log2(r));
  for (int i = 1 << logl; i <= 1 << logr; i <<= 1) {
    a.push_back(i);
  }
  cout << a.size() << '\n';
  for (int i = 0; i < a.size(); i++) {
    cout << a[i] << ' ';
  }
  return 0;
}

T2 词典 \(\texttt{/}\) \(\texttt{dict}\)

题意

超级强化版

正常题意

给定 \(n\) 个字符串 \(s\)\(q\) 次询问,每次询问给定一个字符串 \(t\),问能否进行以下操作最多一次将 \(t\) 变成任意的 \(s\),输出那个 \(s\)(保证唯一);否则输出 No

  • \(t\) 中删除一个字母;

  • \(t\) 中插入一个字母;

  • \(t\) 中修改一个字母。

分析

数据范围很小,所以 unordered_map / map 模拟一下就行了,当然你想用 trie 也没人拦着你

时间复杂度 \(O(\sum |t|)\)\(|t|\) 为字符串 \(t\) 的长度。

寄因

忘记判在最后加上字符的情况。

代码

#include <bits/stdc++.h>

using namespace std;

int n, q;
unordered_map<string, bool> dict;

int main() {
  cin >> n >> q;
  for (int i = 1; i <= n; i++) {
    string s;
    cin >> s;
    dict[s] = 1;
  }
  for (int i = 1; i <= q; i++) {
    string s;
    cin >> s;
    bool f = 1;
    int l = s.size();
    // -----------------------相等--------------------
    if (dict[s]) {
      cout << s << '\n';
      continue;
    }
    // -------------------删去一个字符-----------------
    for (int i = 0; i < l; i++) {
      string s_ = s.substr(0, i) + s.substr(i + 1);
      if (dict[s_]) {
        cout << s_ << '\n';
        f = 0;
        break;
      }
    }
    // -------------------加上一个字符-----------------
    for (char i = 'a'; i <= 'z'; i++) {
      for (int j = 0; j <= l; j++) {
        string s_ = s.substr(0, j) + i + s.substr(j);
        if (dict[s_]) {
          cout << s_ << '\n';
          f = 0;
          break;
        }
      }
    }
    // -------------------修改一个字符-----------------
    for (char i = 'a'; i <= 'z'; i++) {
      for (int j = 0; j < l; j++) {
        string s_ = s;
        s_[j] = i;
        if (dict[s_]) {
          cout << s_ << '\n';
          f = 0;
          break;
        }
      }
    }
    if (f) {
      cout << "No\n";
    }
  }
  return 0;
}

T3 积木 \(\texttt{/}\) \(\texttt{block}\)

题意

现在搭了 \(n\) 列积木,第 \(i\) 列已经搭好的积木高 \(h_i\) 个,在 \(a_{i, j}\) 加上一个积木需要满足 \(a_{i - 1, j}, a_{i, j - 1}, a_{i + 1, j - 1}\) 都已经搭好了,求加上 \(m\) 块积木最大的高度,即 \(\max {h'}_i\)

\(\texttt{p.s:}\ 1 \le n \le 10^5, 1 \le m \le 10^9, 1 \le h_i \le 10^5\)

分析

看了这个数据范围,一眼顶针,望月身亡的,二分 \(m\),然后 \(O(n)\)\(\operatorname{check}\)没了

还有呢!对于 \(O(n)\)\(\operatorname{check}\),实现可以运用单调性,\(L_i\) 表示以 \(i\) 为最高点向两边搭积木的最左边的位置,\(R_i\) 表示以 \(i\) 为最高点向两边搭积木的最左边的位置,\(O(n)\) 求一下 \(L_i,R_i\) 就可以了。

时间复杂度 \(O(n \log m)\)

寄因

没写出来。

代码

#include <cstdio>
#include <vector>
using namespace std;
const long long inf = (long long)2e18;
const int N = 1234567;
int h[N];
vector<int> ev[N];
long long ans[N];
long long sum[N];
int main() {
	int n;
	long long m;
	scanf("%d %lld", &n, &m);
	int l = 0;
	for (int i = 0; i < n; i++) {
		scanf("%d", h + i);
		l = max(l, h[i]);
	}
	int r = (int)l + m;
	while (l < r) {
		int mid = (l + r + 1) >> 1;
		for (int i = 0; i < n; i++) {
			ans[i] = 0;
		}
		for (int rot = 0; rot < 2; rot++) {
			sum[0] = h[0];
			for (int i = 1; i < n; i++) {
				sum[i] = sum[i - 1] + h[i];
			}
			for (int i = 0; i < n; i++) {
				ev[i].clear();
			}
			for (int i = 0; i < n; i++) {
				int j = i + mid - h[i];
				if (j < n) {
					ev[j].push_back(i);
				}
			}
			int mx = -1;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < (int)ev[i].size(); j++) {
					mx = max(mx, ev[i][j]);
				}
				if (mx >= 0) {
					int from = mid - 1;
					int to = mid - (i - mx) + 1;
					ans[i] += (to + from) * 1LL * (from - to + 1) / 2;
					ans[i] -= (sum[i - 1] - sum[mx]);
				} else {
					ans[i] += inf;
				}
			}
			for (int i = 0; i < n - i - 1; i++) {
				swap(h[i], h[n - i - 1]);
				swap(ans[i], ans[n - i - 1]);
			}
		}
		bool found = 0;
		for (int i = 0; i < n; i++) {
			ans[i] += mid - h[i];
			if (ans[i] <= m) {
				found = 1;
				break;
			}
		}
		if (found) {
			l = mid;
		} else {
			r = mid - 1;
		}
	}
	printf("%d\n", l);
	return 0;
}

T4 寻宝 \(\texttt{/}\) \(\texttt{trea}\)

题意

给定一棵树,有点权和边权,求从第 \(i\) 个点出发可以得到的最大的点权(每个点只计算一次) \(-\) 边权的值。

分析

\(f_1(x)\)\(x\) 只往下走回到原点的答案,\(f_2(x)\)\(x\) 只往下走不回到原点的答案。设 \(g_1(x)\)\(x\) 只往上走回到原点的答案,\(g_2(x)\)\(x\) 只往上走不回到原点的答案。第一遍树形 DP 从下往上求出 \(f_1\)\(f_2\)。第二遍树形 DP 从上往下求出 \(g_1\)\(g_2\)。然后就可以求出这个点的答案了。

寄因

没写出来。

代码

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 610000;
int fi[N], ne[N], len[N], to[N];
ll dp0[N], dp1[N];
ll ans[N], wushi0[N], wushi1[N], val[N];
int cnt, n;
void add(int u, int v, int l) {
	cnt++;
	to[cnt] = v;
	len[cnt] = l;
	ne[cnt] = fi[u];
	fi[u] = cnt;
}
void dfs(int u, int fa) {
	ll mx = 0;
	for (int j = fi[u]; j; j = ne[j]) {
		if (to[j] == fa) {
			continue;
		}
		dfs(to[j], u);
		if (dp0[to[j]] - (len[j] << 1) > 0) {
			dp0[u] += dp0[to[j]] - (len[j] << 1);
			mx = max(mx, len[j] + dp1[to[j]] - dp0[to[j]]);
		} else
			mx = max(mx, dp1[to[j]] - len[j]);
	}
	dp0[u] += val[u];
	dp1[u] = dp0[u] + mx;
}
void dfs2(int u, int fa, int le) {
	ans[u] = max(dp0[u] + max(wushi1[u] - le, (ll)0), dp1[u] + max(wushi0[u] - (le << 1), (ll)0));
	ll mx1 = 0, mx2 = 0;
	for (int j = fi[u]; j; j = ne[j]) {
		if (to[j] == fa) {
			continue;
		}
		ll now;
		if (dp0[to[j]] - (len[j] << 1) > 0) {
			now = len[j] + dp1[to[j]] - dp0[to[j]];
		} else {
			now = dp1[to[j]] - len[j];
		}
		if (now > mx1) {
			mx2 = mx1;
			mx1 = now;
		} else if (now > mx2) {
			mx2 = now;
		}
	}
	ll now;
	if (wushi0[u] - 2 * le > 0) {
		now = le + wushi1[u] - wushi0[u];
	} else {
		now = wushi1[u] - le;
	}
	if (now > mx1) {
		mx2 = mx1;
		mx1 = now;
	} else if (now > mx2) {
		mx2 = now;
	}
	for (int j = fi[u]; j; j = ne[j]) {
		if (to[j] == fa) {
			continue;
		}
		wushi0[to[j]] = dp0[u] - max((ll)0, dp0[to[j]] - (len[j] << 1)) + max((ll)0, wushi0[u] - (le << 1));
		ll now;
		if (dp0[to[j]] - (len[j] << 1) > 0) {
			now = len[j] + dp1[to[j]] - dp0[to[j]];
		} else {
			now = dp1[to[j]] - len[j];
		}
		if (now == mx1) {
			wushi1[to[j]] = wushi0[to[j]] + mx2;
		} else {
			wushi1[to[j]] = wushi0[to[j]] + mx1;
		}
	}
	for (int j = fi[u]; j; j = ne[j]) {
		if (to[j] != fa) {
			dfs2(to[j], u, len[j]);
		}
	}
}
int main() {
	cin >> n;
	for (int i = 1; i < n; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		add(u, v, w);
		add(v, u, w);
	}
	for (int i = 1; i <= n; i++) {
		cin >> val[i];
	}
	dfs(1, 0);
	for (int j = fi[1]; j; j = ne[j]) {
		if (dp0[to[j]] - 2 * len[j] > 0) {
			wushi0[to[j]] = dp0[1] - (dp0[to[j]] - 2 * len[j]);
		} else {
			wushi0[to[j]] = dp0[1];
		}
	}
	ll mx1 = 0, mx2 = 0;
	for (int j = fi[1]; j; j = ne[j]) {
		ll now;
		if (dp0[to[j]] - (len[j] << 1) > 0) {
			now = len[j] + dp1[to[j]] - dp0[to[j]];
		} else {
			now = dp1[to[j]] - len[j];
		}
		if (now > mx1) {
			mx2 = mx1;
			mx1 = now;
		} else if (now > mx2) {
			mx2 = now;
		}
	}
	for (int j = fi[1]; j; j = ne[j]) {
		ll now;
		if (dp0[to[j]] - 2 * len[j] > 0) {
			now = len[j] + dp1[to[j]] - dp0[to[j]];
		} else {
			now = dp1[to[j]] - len[j];
		}
		if (now == mx1) {
			wushi1[to[j]] = wushi0[to[j]] + mx2;
		} else {
			wushi1[to[j]] = wushi0[to[j]] + mx1;
		}
	}
	ans[1] = dp1[1];
	for (int j = fi[1]; j; j = ne[j]) {
		dfs2(to[j], 1, len[j]);
	}
	for (int i = 1; i <= n; i++) {
		cout << ans[i] << '\n';
	}
	return 0;
}
posted @ 2023-10-05 17:17  Yun_Mengxi  阅读(28)  评论(0)    收藏  举报