A Don’t Starve

题意:给定平面上 nnn 个点,从原点出发直线前往这些点收集食物,收集完再前往下一个点。每当离开一个有食物的点后该点食物刷新,每次移动距离严格下降。问最多收集到多少食物。n≤2×103n \leq 2\times 10^3n≤2×103。

解法:根据距离作为边权构建完全图,按照边权从大到小排序。记 fif_{i}fi​ 为到达 iii 点时收集到的最大食物数量,则当边距离从大到小考虑时,对于边 (u,v)(u,v)(u,v),其唯一可行转移为 fv←max⁡(fv,fu+1)f_v \leftarrow \max(f_v,f_u +1)fv​←max(fv​,fu​+1),因为此时从原点到达 vvv 的路径上边权一定大于等于 (u,v)(u,v)(u,v) 边权。对于边权相等的一系列边,需要同时处理,因为距离严格相等,不可以互相转移。总时间复杂度 O(n2log⁡n+n2)\mathcal O(n^2 \log n +n^2)O(n2logn+n2)。

#include <bits/stdc++.h>
using namespace std;
const int N = 2000;
const int inf = 0x3f3f3f3f;
int x[N + 5], y[N + 5], f[N + 5], g[N + 5];
struct line
{int from, to;int dis;bool operator<(const line &b)const{return dis > b.dis;}line(int _from, int _to, int _dis){from = _from;to = _to;dis = _dis;}
};
int main()
{int n;scanf("%d", &n);for (int i = 1; i <= n;i++)scanf("%d%d", &x[i], &y[i]);vector<line> que;for (int i = 0; i <= n;i++)for (int j = 1; j <= n;j++)if (i != j)que.emplace_back(i, j, (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));sort(que.begin(), que.end());for (int i = 1; i <= n;i++)f[i] = -inf;int m = que.size();for (int i = 0; i < m;){int j = i;while (j < m && que[i].dis == que[j].dis){g[que[j].to] = -inf;j++;}for (int k = i; k < j;k++)g[que[k].to] = max(g[que[k].to], f[que[k].from] + 1);for (int k = i; k < j;k++)f[que[k].to] = max(f[que[k].to], g[que[k].to]);i = j;}int ans = 0;for (int i = 1; i <= n; i++)ans = max(ans, f[i]);printf("%d", ans);return 0;
}

C Bit Transmission

题意:有一个长度为 nnn 的 01 串,进行 3n3n3n 次询问,得到位置 xxx 是否为 111 的回答。若回答机器只会回答错误一次,问能否确定这一字符串。n≤1×105n \leq 1\times 10^5n≤1×105。

解法:对于每一位单独考虑,记第 iii 位答案为 000 次数为 c0c_0c0​,111 次数为 c1c_1c1​。

  1. c0=c1=0c_0=c_1=0c0​=c1​=0。则该位无法判断。
  2. c0,c1≥2c_0,c_1 \geq 2c0​,c1​≥2。说谎次数必然超过一次,无解。
  3. c0c_0c0​ 与 c1c_1c1​ 中有一个为 111 另一个为 000。根据有无说谎判断,无说谎则无解。
  4. c0,c1c_0,c_1c0​,c1​ 中有一个大于等于 222 另一位为 000。必然没说谎。
  5. c0,c1c_0,c_1c0​,c1​ 中有一个大于等于 222,另一个为 111。必然说谎。
#include <bits/stdc++.h>
using namespace std;
const int N = 300000;
int cnt[N + 5][2];
char buf[10];
char s[N + 5];
int main()
{int n;scanf("%d", &n);for (int i = 1, x; i <= 3 * n;i++){scanf("%d%s", &x, buf);if (x < n)cnt[x][buf[0] == 'Y']++;}bool flag = 1, once = 0;int lie = -1;for (int i = 0; i < n;i++){if(!cnt[i][0] && !cnt[i][1]){printf("-1");return 0;}if ((cnt[i][0] >= 2 && cnt[i][1] >= 2) || (cnt[i][0] == 1 && cnt[i][1] == 1)){printf("-1");return 0;}if(cnt[i][0] == 0 && cnt[i][1]){once |= cnt[i][1] == 1;s[i] = '1';}else if(cnt[i][1] == 0 && cnt[i][0]){once |= cnt[i][0] == 1;s[i] = '0';}else{if (lie != -1){printf("-1");return 0;}lie = i;if(cnt[i][0] >= 2)s[i] = '0';elses[i] = '1';}}if (lie == -1 && once)printf("-1");elseprintf("%s", s);return 0;
}

D Birds in the tree

题意:给定 nnn 个节点的树,树上每个点为 0,10,10,1 两种颜色之一。问树上连通块满足该连通块构成的生成子图中度为 111 节点均同色的方案数。n≤3×105n \leq 3\times 10^5n≤3×105。

解法:考虑 fu,0/1f_{u,0/1}fu,0/1​ 表示 uuu 子树下,必然含有 uuu 在连通块内,连通块叶子颜色为 0/10/10/1 的连通块个数。设 uuu 的颜色为 000(111 同理),则有
fu,0=∏v∈childu(fv,0+1)fu,1=(∏v∈childu(fv,1+1))−∑v∈childufv,1−1f_{u,0}=\prod_{v \in {\rm child}_u} (f_{v,0}+1)\\ f_{u,1}=\left(\prod_{v \in {\rm child}_u} (f_{v,1}+1)\right)-\sum_{v \in {\rm child}_u}f_{v,1}-1\\ fu,0​=v∈childu​∏​(fv,0​+1)fu,1​=(v∈childu​∏​(fv,1​+1))−v∈childu​∑​fv,1​−1
其中 fu,0f_{u,0}fu,0​ 的含义为:每个子树中连通块叶子颜色为 000 的方案必然均可选,并且可以不选;

fu,1f_{u,1}fu,1​ 则必然要求在大于等于两个子树内均有选择 111 作为叶子颜色的,使得 uuu 不作为叶子节点出现,因而减去仅在一个子树内任取的方案。并且不能以 uuu 一个单节点作为叶子颜色为 111 的情况出现。最后答案为 ∑i=1nfi,0+fi,1\displaystyle \sum_{i=1}^n f_{i,0}+f_{i,1}i=1∑n​fi,0​+fi,1​。

#include <bits/stdc++.h>
using namespace std;
const int N = 300000;
const long long mod = 1000000007;
long long ans;
struct line
{int from;int to;int next;
};
struct line que[2 * N + 5];
int cnt, headers[N + 5];
void add(int from, int to)
{cnt++;que[cnt].from = from;que[cnt].to = to;que[cnt].next = headers[from];headers[from] = cnt;
}
int col[N + 5];
char s[N + 5];
long long f[N + 5][2];
void dfs(int place, int father)
{long long sum = 0;f[place][0] = f[place][1] = 1;for (int i = headers[place]; i; i = que[i].next)if (que[i].to != father){dfs(que[i].to, place);f[place][0] = f[place][0] * (1 + f[que[i].to][0]) % mod;f[place][1] = f[place][1] * (1 + f[que[i].to][1]) % mod;sum = (sum + f[que[i].to][col[place] ^ 1]) % mod;}f[place][col[place] ^ 1]--;ans = (ans + f[place][0] + f[place][1] - sum + mod) % mod;
}
int main()
{int n;scanf("%d%s", &n, s + 1);for (int i = 1; i <= n;i++)col[i] = s[i] == '1';for (int i = 1, u, v; i < n;i++){scanf("%d%d", &u, &v);add(u, v);add(v, u);}dfs(1, 1);printf("%lld", ans);return 0;
}

E Fraction Game

题意:给定 n×nn \times nn×n 的三角形数组,问 k×kk\times kk×k 的三角形区域内最大值的和。1≤k≤n≤1×1031\leq k \leq n \leq 1\times 10^31≤k≤n≤1×103。

解法:考虑倍增。朴素的倍增为二倍增,即覆盖区域边长扩大两倍。但是容易发现,如果只是朴素的转移,即 fi,j←max⁡(fi−k,j,fi,j,fi,j+k)f_{i,j} \leftarrow \max(f_{i-k,j},f_{i,j},f_{i,j+k})fi,j​←max(fi−k,j​,fi,j​,fi,j+k​),这样会有一个倒三角区域无法覆盖。此处有两种解决方案:

  1. 扩大转移范围。想要完全覆盖,可以改写方程为:
    fi,j=max⁡(fi−k,jmax⁡l=0kfi+l,j)f_{i,j}=\max\left(f_{i-k,j}\max_{l=0}^k f_{i+l,j}\right) fi,j​=max(fi−k,j​l=0maxk​fi+l,j​)
    这样就可以实现完全覆盖,但是这样每次转移量是 O(k)O(k)O(k) 的。注意到这样的转移每次长度是固定的,因而考虑滑动窗口去解决,均摊 nnn 次转移项仅需 O(n)O(n)O(n) 次。

  2. 修改倍增大小。考虑可以完全覆盖的最大倍数:下图中三个大三角形完全相似,因而容易计算出最外侧的三角形与三个大三角形的相似比为 32\dfrac{3}{2}23​,因而覆盖边长为 xxx 扩张到 ⌈3x2⌉\left \lceil \dfrac{3x}{2}\right \rceil⌈23x​⌉。

对于恰好为 kkk 的转移只需要单独做一次扩张即可。总复杂度 O(n2log⁡n)\mathcal O(n^2 \log n)O(n2logn)。

// 1.5 倍增
#include <bits/stdc++.h>
#define fp(i, a, b) for (int i = a, i##_ = (b) + 1; i < i##_; ++i)
#define fd(i, a, b) for (int i = a, i##_ = (b) - 1; i > i##_; --i)using namespace std;
const int N = 1005;
using ll = int64_t;
struct Frac {ll x, y;Frac(ll a = 0, ll b = 1) { y = __gcd(a, b), x = a / y, y = b / y; }bool operator<(const Frac a) const { return x * a.y < y * a.x; }Frac operator+(const Frac a) const { return Frac(x * a.y + y * a.x, y * a.y); }
} f[N][N];
int n, k, pw[20], Log[N];
void Solve() {scanf("%d%d", &n, &k);Frac ans;fp(i, 1, n) fp(j, 1, i)scanf("%lld/%lld", &f[i][j].x, &f[i][j].y);fp(t, 1, Log[k]) {int pk = pw[t] - pw[t - 1];fp(i, 1, n - pk) fp(j, 1, i)f[i][j] = max({f[i][j], f[i + pk][j], f[i + pk][j + pk]});}int pk = pw[Log[k]];fp(i, 1, n - k + 1) fp(j, 1, i)ans = ans + max({f[i][j], f[i + k - pk][j + k - pk], f[i + k - pk][j]});printf("%lld/%lld\n", ans.x, ans.y);
}
int main() {pw[0] = 1;fp(i, 1, 15) Log[pw[i] = (3 * pw[i - 1] + 1) >> 1] = i;fp(i, 2, N - 1) Log[i] = max(Log[i], Log[i - 1]);int t = 1;while (t--) Solve();return 0;
}
//二倍增+单调队列
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
struct Frac {long long x, y;Frac(long long a = 0, long long b = 1) { y = __gcd(a, b), x = a / y, y = b / y; }bool operator==(const Frac a) const { return x * a.y == y * a.x; }bool operator<(const Frac a) const { return x * a.y < y * a.x; }Frac operator+(const Frac a) const { return Frac(x * a.y + y * a.x, y * a.y); }bool operator<=(const Frac a) const { return *this < a || *this == a; }bool operator>(const Frac a) const { return x * a.y > y * a.x; }bool operator>=(const Frac a) const { return *this > a || *this == a; }
} f[N + 5][N + 5];
int main()
{int n, k;scanf("%d%d", &n, &k);for (int i = 1; i <= n;i++)for (int j = 1; j <= i;j++)scanf("%lld/%lld", &f[i][j].x, &f[i][j].y);int p = 2;for (; p < k; p *= 2)for (int x = 1; x <= n - p + 1; x++){deque<int> q;for (int i = 1; i <= p / 2; i++){while (!q.empty() && f[x + p / 2][i] >= f[x + p / 2][q.back()])q.pop_back();q.push_back(i);}for (int y = 1; y <= x; y++){while (!q.empty() && q.front() < y)q.pop_front();while (!q.empty() && f[x + p / 2][y + p / 2] >= f[x + p / 2][q.back()])q.pop_back();q.push_back(y + p / 2);f[x][y] = max(f[x][y], f[x + p / 2][q.front()]);}}p /= 2;Frac ans;for (int x = 1; x <= n - k + 1; x++){deque<int> q;for (int i = 1; i <= k - p; i++){while (!q.empty() && f[x + k - p][i] >= f[x + k - p][q.back()])q.pop_back();q.push_back(i);}for (int y = 1; y <= x; y++){while (!q.empty() && q.front() < y)q.pop_front();while (!q.empty() && f[x + k - p][y + k - p] >= f[x + k - p][q.back()])q.pop_back();q.push_back(y + k - p);// printf("X:%d Y:%d ANS:%lld\n", x, y, max(f[x][y], f[x + k - p][q.front()]));ans = ans + max(f[x][y], f[x + k - p][q.front()]);}}printf("%lld/%lld", ans.x, ans.y);return 0;
}

F A Stack of CDs

题意:给定平面 nnn 个圆,后面的圆会覆盖遮挡前面的圆。问这些圆从上面能看到的周长。n≤1×103n \leq 1\times 10^3n≤1×103。

解法:考虑对于第 iii 个圆能看到的周长,只由 j(j>i)j(j>i)j(j>i) 的圆决定。对于一对圆 (i,j)(i,j)(i,j),若 iii 圆被完全覆盖则看不到,相离则没有影响,否则考虑相交的情况。

记两圆距离为 ddd,则 β=∠AOiOj\beta=\angle AO_iO_jβ=∠AOi​Oj​ 由余弦定理得到:cos⁡∠AOiOj=ri2+d2−rj22dri\cos \angle AO_iO_j=\dfrac{r_i^2+d^2-r_j^2}{2dr_i}cos∠AOi​Oj​=2dri​ri2​+d2−rj2​​。同时计算 OiOjO_iO_jOi​Oj​ 的极角 α\alphaα,则遮挡角度范围为 [α−β,α+β][\alpha-\beta,\alpha+\beta][α−β,α+β]。注意将其化到 [−π,π][-\pi,\pi][−π,π] 的范围即可。剩下的就是对于每个圆的遮挡部分进行线段合并再求和,与第一场 A 题完全相同。

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
struct circle
{double x, y;double r;vector<pair<double, double>> ban;
};
int main()
{int n;scanf("%d", &n);vector<circle> que(n);for (int i = 0; i < n;i++)scanf("%lf%lf%lf", &que[i].x, &que[i].y, &que[i].r);for (int i = 0; i < n;i++)for (int j = i + 1; j < n;j++){double r1 = que[i].r, r2 = que[j].r, x1 = que[i].x, x2 = que[j].x, y1 = que[i].y, y2 = que[j].y;double dis = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));if (dis <= r1 + r2 && abs(r1 - r2) <= dis){double cen = atan2(y2 - y1, x2 - x1);double ang = acos((dis * dis + r1 * r1 - r2 * r2) / (2 * dis * r1));double low = cen - ang, high = cen + ang;if (cen - ang < -pi){que[i].ban.emplace_back(cen - ang + 2 * pi, pi);low = -pi;}if(cen + ang > pi){que[i].ban.emplace_back(-pi, cen + ang - 2 * pi);high = pi;}que[i].ban.emplace_back(low, high);}else if(dis < abs(r1 - r2) && r1 <= r2)que[i].ban.emplace_back(-pi, pi);}double ans = 0;for (auto &cir : que){sort(cir.ban.begin(), cir.ban.end());if(cir.ban.empty()){ans += cir.r * 2 * pi;continue;}int m = cir.ban.size();double len = 0;for (int i = 0; i < m;){int j = i;double nowr = cir.ban[i].second;while (j < m && cir.ban[j].first <= nowr){nowr = max(nowr, cir.ban[j].second);j++;}len += nowr - cir.ban[i].first;assert(i < j);i = j;}ans += (2 * pi - len) * cir.r;}printf("%.10lf", ans);return 0;
}

I Board Game

题意:nnn 个士兵要分为 mmm 组,每次每一个活着的士兵可以对敌人造成 111 点伤害,敌人会选择一组杀掉至多 kkk 个士兵。当士兵死完后游戏结束,敌人以最优打法打,问最大造成的伤害。n≤1×109n \leq 1\times 10^9n≤1×109,m,k≤1×107m,k \leq 1\times 10^7m,k≤1×107。

解法:敌人的最优解永远都是挑最多的一组,能杀多少杀多少,因而当两组士兵人数均不足 kkk 人时,若人数为 x1,x2x_1,x_2x1​,x2​,则最优解一定是 x1=x2x_1=x_2x1​=x2​ 或 x1=x2+1x_1=x_2+1x1​=x2​+1。

首先人数超过 2mk2mk2mk 人是没有意义的:每组多加 kkk 人只会拖延敌人 mmm 轮进攻。因而首先将这部分人抹去,仅考虑 n′=n−(⌊nmk⌋−1)mkn'=n-\left(\left \lfloor \dfrac{n}{mk}\right \rfloor-1\right)mkn′=n−(⌊mkn​⌋−1)mk 人。考虑接下来的这些人中有多少组会超过 kkk 人,假设有 iii 组,则剩余的 n′−kin'-kin′−ki 人一定是均匀分配——根据刚刚的推论,当每一组超过 kkk 人的都死了,剩下的一定是均匀分配。因而只需要枚举这个 iii 即可。时间复杂度 O(m)\mathcal O(m)O(m)。

#include <bits/stdc++.h>
using namespace std;
long long lim, m, k;
long long cal(long long n)//计算人数不超过2mk时的攻击伤害
{long long res = n % m, lcnt = m - res, lower = n / m, upper = lower + 1;return lower * res * lcnt + res * (res + 1) / 2 * upper + lcnt * (lcnt + 1) / 2 * lower;
}
void print(long long now)
{if (now >= lim)printf("YES %lld", now);elseprintf("NO");
}
int main()
{long long n;scanf("%lld%lld%lld%lld", &n, &m, &k, &lim);if (n <= m * k){print(cal(n));return 0;}long long whole = n / (m * k) - 1;n -= whole * m * k;long long ans = n * whole * m + k * m * whole * (m * whole + 1) / 2, maximum = 0;for (int i = 0; i <= m && i * k <= n; i++){long long now = n - i * k;maximum = max(maximum, now * i + k * (i + 1) * i / 2 + cal(now));}print(ans + maximum);return 0;
}

2022 年牛客多校第五场补题记录相关推荐

  1. 2022 年牛客多校第四场补题记录

    A Task Computing 题意:给定长度为 nnn 的序列 {(wi,pi)}\{(w_i,p_i)\}{(wi​,pi​)},从中选出 mmm 项并重新排列得到子序列 {a1,a2,⋯,am ...

  2. 2022年牛客多校第三场补题记录

    A Ancestor 题意:给出两棵 nnn 个节点的树 A,BA,BA,B,A,BA,BA,B 树上每个节点均有一个权值,给出 kkk 个关键点的编号 x1,x2,⋯,xkx_1, x_2, \cd ...

  3. 2021牛客多校第五场补题

    B-Boxes 链接:https://ac.nowcoder.com/acm/contest/11256/B 来源:牛客网 题目描述 There're nn_{}n​ boxes in front o ...

  4. 2021牛客多校第八场补题 D-OR

    链接:https://ac.nowcoder.com/acm/contest/11259/D 来源:牛客网 题目描述 There are two sequences of length n−1n-1n ...

  5. 2020年牛客多校第五场C题-easy(纯组合计数不要生成函数的做法)

    文章目录 description solution code description 有TTT组测试数据 对于两个长度为KKK的数列{a}\{a\}{a}和{b}\{b\}{b},满足∑i=1Kai= ...

  6. 2022 年杭电多校第八场补题记录

    A Theramore 题意:给定一个长度为 nnn 的 010101 串,每次可以选取一个奇数长度的连续子串进行位置上的翻转,问经过若干次操作能得到的字典序最小的串.n≤5×105n \leq 5\ ...

  7. 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数

    目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...

  8. subsequence 1(牛客多校第五场记忆化搜索+组合数学)

    链接:https://ac.nowcoder.com/acm/contest/885/G 来源:牛客网 题目描述 You are given two strings s and t composed ...

  9. 2019牛客多校训练营第一场 H题 HOR 题解

    题目描述: 输入描述: 输出描述: 示例1: 题解: 更多问题可关注牛客竞赛区,一个刷题.比赛.分享的社区. 传送门:https://ac.nowcoder.com/acm/contest/discu ...

  10. 2019牛客多校训练营第一场 E题 ABBA 题解

    问题描述: 输入描述: 输出描述: 示例1: 题解: 更多问题可关注牛客竞赛区,一个刷题.比赛.分享的社区. 传送门:https://ac.nowcoder.com/acm/contest/discu ...

最新文章

  1. gdb 查找动态库方法
  2. t-SNE algorithm(t-分布邻域嵌入算法)
  3. 37 windows_37_Thread_InterLock 线程-原子锁
  4. yield python3 知乎_运维学python之爬虫高级篇(七)scrapy爬取知乎关注用户存入mongodb...
  5. 【数据结构作业心得】4-0 二叉树
  6. MySQL系列:innodb源代码分析之线程并发同步机制
  7. 阿里:千亿交易背后的0故障发布
  8. jQuery的hide() 、show() 、toggle()
  9. 科技公司都是如何应对 COVID-19?
  10. 【每日算法Day 81】面试经典题:关于丑数,你真的理解为什么这么算吗?
  11. 报错解决:ninja: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20‘ not found (required by ninja)
  12. Web 渗透之信息收集
  13. sql常用语句整理(包括增删改查),适合小白使用
  14. GaussDB (for Cassandra) 数据库治理:大key与热key问题的检测与解决
  15. 数字转为人民币大写汉字输出(大力看了都喊nb的详细教程)
  16. GAN(Generative Adversarial Nets)详细分析
  17. 6.1 Verbatim环境
  18. python中如何输出空格换行_Python将文件中空格变成换行的方法如何做
  19. 互联网协议 — Ethernet — 网络数据报文的传输方式
  20. SAP770系统FI模块配置(给科目表分配公司代码)

热门文章

  1. 看完你就明白的锁系列之自旋锁
  2. 【加密算法】3DES加密算法
  3. android短信过滤关键词,iOS 11的垃圾短信按关键词过滤功能使用介绍
  4. ipv6环境搭建来测试
  5. 计算机打表格图,快速填充/微图表/一秒制作打勾方框
  6. C/C++基础题029.DDD
  7. 查看Win7的真实版本号方法
  8. 趣味点名软件_网传川大教授用刷脸软件点名 学生无人敢逃课
  9. comsol学习之模拟杯中水对流-二维轴对称流体传热
  10. 33种化学原理动图, 让你秒懂化学反应原理!