A:
题目大意:给你一个数字串,每个数字只可以用一次,求最多可以组成多少个电话号码(可以相同),电话号码第一个数字为$8$,且长度为$11$
题解:限制为$8$的个数和总长度,直接求
卡点:无
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 1000 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} int Tim, n, _8; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for (int i = 1; i <= n; i++) if (s[i] == ‘8‘) _8++; printf("%d\n", min(_8, n / 11)); return 0; }
B:
题目大意:给你一个数$x$,求两个数$a,b$,使得$a+b=n$,且价值和最大,$a$的价值定义为它各个数位上的数字和
题解:$a$尽可能多分$9$,$b$为$x-a$
卡点:无
C++ Code:
#include <cstdio> #include <algorithm> inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} long long n, a, b, len; long long ans; inline int count(long long a) { int ans = 0; while (a) { ans += a % 10; a /= 10; } return ans; } int main() { scanf("%I64d", &n); long long nn = n; while (nn) { len++; nn /= 10; } ans = (len - 1) * 9; for (int i = 1; i < len; i++) a = a * 10 + 9; ans += count(n - a); printf("%I64d\n", ans); return 0; }
C:
题目大意:给定$a_1,a_2,\dots,a_n$和$b_1,b_2,\dots,b_m$。$c_{i,j}=a_ib_j$。
给定$x$,求四个数$x_1,y_1,x_2,y_2$满足:
$\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y_2}c_{i,j}\leqslant x$。
对于每个满足条件的四元组$(x_1,y_1,x_2,y_2)$,定义其价值为$(x_2-x_1+1)\times(y_2-y_1+1)$,求最大价值。
题解:
$$
\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y2}c_{i,j}=\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y2}a_ib_j=(\sum_{i=x_1}^{x_2}a_i)(\sum_{j=y_1}^{y_2}b_j)
$$
记录下每个$x_2-x_1+1$对应最小的$\sum_{i=x_1}^{x_2}a_i$,每个$y_2-y_1+1$对应最小的$\sum_{j=y_1}^{y_2}b_j$,枚举,找最大的即可。
卡点:无
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 2010 const long long inf = 0x3f3f3f3f3f3f3f3f; inline long long min(long long a, long long b) {return a < b ? a : b;} inline long long max(long long a, long long b) {return a > b ? a : b;} int a[maxn], b[maxn]; long long sa[maxn], sb[maxn], ans, x; long long A[maxn], B[maxn]; int n, m; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", a + i), sa[i] = sa[i - 1] + a[i]; for (int i = 1; i <= m; i++) scanf("%d", b + i), sb[i] = sb[i - 1] + b[i]; scanf("%I64d", &x); for (int i = 1; i <= n; i++) { A[i] = inf; for (int j = 1; j <= n - i + 1; j++) { A[i] = min(sa[i + j - 1] - sa[j - 1], A[i]); } // printf("A[%d] : %lld\n", i, A[i]); } for (int i = 1; i <= m; i++) { B[i] = inf; for (int j = 1; j <= m - i + 1; j++) { B[i] = min(sb[i + j - 1] - sb[j - 1], B[i]); } // printf("A[%d] : %lld\n", i, B[i]); } ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (A[i] * B[j] <= x) ans = max(ans, i * j); } } printf("%I64d\n", ans); return 0; }
D:
题目大意:有$n$个人,坐成若干圈(每人面对圈中间)。第$i$个人左边要有$l_i$个空位,右边要有$r_i$个空位。问至少要多少个座位。
题解:考虑把$l_i$和$r_i$分别看成一个点,则原题变为一张二分图。要求找到一个匹配,每条边的价值为$\max(l_x,r_y)+1$,使得价值最小。
也就是要求“浪费”最少,即按$l$和$r$分别排序,最小连最小,次小连次小……
卡点:前两次没猜中结论。。。
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 100010 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} int n; long long l[maxn], r[maxn], ans, tmpl, tmpr; int rnkl[maxn], rnkr[maxn], totl, totr; bool vl[maxn], vr[maxn]; inline bool cmpl(int a, int b) {return l[a] < l[b];} inline bool cmpr(int a, int b) {return r[a] < r[b];} long long sum; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%I64d%I64d", l + i, r + i); std::sort(l + 1, l + n + 1); std::sort(r + 1, r + n + 1); for (int i = 1; i <= n; i++) ans += max(l[i], r[i]); printf("%I64d\n", ans + n); return 0; }
E:
题目大意:一棵树。可以在任意两个在原树中距离为$2$的点之间连一条边。求所有点对间最短路的和。
题解:
$$
\begin{align*}
ans&=\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^n\left\lceil\dfrac{dis_{i,j}}{2}\right\rceil\\
&=\dfrac{\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^ndis_{i,j}+奇数的路径数目}{2}\\
\end{align*}\\
$$
易证,求出来的一定是整数
卡点:没开$long\;long$,被$FST$了
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 200010 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} int n; int head[maxn], cnt = 1; struct Edge { int to, nxt; } e[maxn << 1]; inline void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; // e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } long long ans, ansji; int fa[maxn]; long long uji[maxn], uou[maxn], dji[maxn], dou[maxn], sz[maxn]; void dfs1(int u) { sz[u] = 1; dou[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[u]) { fa[v] = u; dfs1(v); ans += 1ll * sz[v] * (n - sz[v]); sz[u] += sz[v]; ansji += dji[v] * dji[u] + dou[u] * dou[v]; dou[u] += dji[v]; dji[u] += dou[v]; } } } int main() { scanf("%d", &n); for (int i = 1, a, b; i < n; i++) { scanf("%d%d", &a, &b); add(a, b); add(b, a); } dfs1(1); printf("%I64d\n", (ans + ansji >> 1ll)); return 0; }
原文地址:https://www.cnblogs.com/Memory-of-winter/p/9744854.html