2022牛客多校(加赛)

2022牛客多校(加赛)

一、比赛小结

比赛链接:"蔚来杯"2022牛客暑期多校训练营(加赛)

二、题目分析及解法(基础题)

E、Everyone is bot

题目链接:E-Everyone is bot

题意:

复读游戏,有 n 个人打算在群里复读。

一次复读的过程如下:

每一轮,n 个人按照编号从小到大依次执行以下操作。

如果这个人在前几轮已经进行过复读,他不会再次复读。也就是说,每

个人最多只会复读一次。

否则他可以选择是否进行复读。

如果某一轮没有人进行复读,那么复读的过程结束。

题解:

对于第 i 个人,如果他是所有人中第 j 个进行复读的,他会获得 ai,j 瓶冰红茶。

但是如果他是所有进行了复读的人当中倒数第 p 个进行复读的人,那么

他不会获得任何冰红茶,并且需要交给咩噗特雷格博 bot 154 瓶冰红茶(即获得 −154 杯冰红茶)。

每个人都想最大化自己获得的冰红茶数量,求所有人一共会拿到多少冰红茶。

总复读人数是 n mod p。

如果当前已经有 n − p 个人复读了,那么后面不会有任何人复读。一旦有人复读,剩下的人必然都会参与复读,那么这个人就会被禁言。所以他不会这么做。

同样,如果有 n − 2p 个人复读了,那么后面不会有任何人复读,因为一旦他复读了,接下来一定有 p − 1 个人加入复读,而这时候是 n − p 个人复读的状态,剩下 p 个人一定不会复读,那么他就被禁言了。

同样可以推出,如果当前复读人数是 n − kp 那么后面不会有人复读。

前 n mod p 个人必然一上来就复读。可以考虑如果有人不复读,后面本来没有机会的人必然会抓住机会,那么前面有人就会失去机会。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
int n, p;
int a[maxn][maxn];
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> p;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++) cin >> a[i][j];
  for (int i = 1; i <= n % p; i++) cout << a[i][i] << " ";
  for (int i = n % p + 1; i <= n; i++) cout << 0 << " ";
  cout << endl;
  return 0;
}

H、Here is an Easy Problem of Zero-chan

题目链接:H-Here is an Easy Problem of Zero-chan

题意:

有一颗 n 个节点且以 1 为根的有根树。第 i 个点的点权为 i。多次查询编号为 x 的点, ∏ i = 1 n l c a ( i , x ) \prod_{i=1}^nlca(i, x) i=1nlca(i,x) 的末尾有多少个零。

题解:

首先对于数 a a a 末尾有 x x x 个零等价于他能分解成 a ′ × 10 x a′ × 10x a×10x x x x 的最大值。因为对于 x x x 进制而言,乘以 x x x 相当于将数字左移一位,然后末尾补 0 0 0 。问题便转变成了求 ∏ i = 1 n l c a ( i , x ) \prod_{i=1}^nlca(i, x) i=1nlca(i,x) 能分解出多少个 10 10 10 作为因子,而 10 10 10 的因子为 2 2 2 5 5 5 ,所以等价于求上式能分解出的 2 2 2 5 5 5 的最小值。随后我们可以将点分为两类,对于处于 x 的子树内的点,与 x 的 lca 均为 x,而不处于 x 的子树内的点,那么他们的 lca 均为 x 的祖先。

所以对于查询 x 而言,我们可以枚举 x 到根节点的所有节点,对于每个点计算有多少个点与 x 不在同一个儿子子树内。对于上述解法的时间复杂度上界为 n 2 n^2 n2 ,此时我们可以发现,对于点 x,他的父亲节点 f a x fa_x fax 对于祖先路径上的权值计算与 x 相同,所以我们可以采用树形 dp 来减少重复的计算。则可以得到转移式 d p x = d p f a x + s i z e x × ( c n t x 2 ∣ 5 − c n t f a x 2 ∣ 5 ) dp_x = dp_{fa_x} + size_x × (cnt_{x2|5} − cnt_{fa_x2|5}) dpx=dpfax+sizex×(cntx2∣5cntfax2∣5) ,其中 s i z e x size_x sizex 代表 x 的子树大小, c n t x 2 ∣ 5 cnt_{x2|5} cntx2∣5 代表节点 x 能分解出多少个 2 或 5。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct e {
  int to, next;
} edge[maxn << 1];
int head[maxn], cnt;
int n, q;
int num[maxn];
int f2[maxn], f5[maxn];
int ans2[maxn], ans5[maxn];
void init() {
  cnt = 0;
  memset(head, -1, sizeof(head));
  for (int i = 1; i < maxn; i++) {
    if (i % 2 == 0) f2[i] = f2[i / 2] + 1;
    if (i % 5 == 0) f5[i] = f5[i / 5] + 1;
  }
}
void addedge(int u, int v) {
  edge[cnt] = e{v, head[u]};
  head[u] = cnt++;
}
void predfs(int u, int fa) {
  num[u] = 1;
  for (int i = head[u]; i != -1; i = edge[i].next) {
    int v = edge[i].to;
    if (v == fa) continue;
    predfs(v, u);
    num[u] += num[v];
  }
}
void dfs(int u, int fa) {
  ans2[u] = ans2[fa] + (f2[u] - f2[fa]) * num[u];
  ans5[u] = ans5[fa] + (f5[u] - f5[fa]) * num[u];
  for (int i = head[u]; i != -1; i = edge[i].next) {
    int v = edge[i].to;
    if (v == fa) continue;
    dfs(v, u);
  }
}
int main() {
  clock_t startTime = clock();
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
  init();
  cin >> n >> q;
  for (int i = 1; i < n; i++) {
    int u, v;
    cin >> u >> v;
    addedge(u, v), addedge(v, u);
  }
  predfs(1, 0);
  dfs(1, 0);
  while (q--) {
    int x;
    cin >> x;
    int ans = min(ans2[x], ans5[x]);
    cout << ans << endl;
  }
  clock_t endTime = clock();
  // cout << "Time: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s"
  //      << endl;
  return 0;
}

J、Jellyfish and its dream

题目链接:J-Jellyfish and its dream
题意:

给一个序列,值域为 0 ∼ 2。如果 ( a i + 1 ) ( m o d 3 ) = a i + 1 ( m o d n ) (a_i + 1) \pmod 3 = a_{i+1} \pmod n (ai+1)(mod3)=ai+1(modn) ,就可以将 a i a_i ai 赋值为 ( a i + 1 ) ( m o d 3 ) (a_i + 1) \pmod 3 (ai+1)(mod3) 。问有限次操作后是否能使所有元素均相等。

题解:

差分,后文中的变化全部指差分数组。一次操作可以将相邻的 (2, 1) 变成 (0, 0),(1, 1) 变成 (2, 0),(0, 1) 变成(1, 0)。不难发现 0 没有意义。可以通过 (0, 1) 变成 (1, 0)这个操作来移动 1的位置。只要 1 的数量不少于 2 的数量即可。
代码:

M、Maimai DX 2077

题目链接:M-Maimai DX 2077

题意:

音游大模拟
题解:

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
double a[10][10] = {{1, 1, 0.8, 0.5, 0},
                    {2, 2, 1.6, 1.0, 0},
                    {3, 3, 2.4, 1.5, 0},
                    {5, 5, 2.5, 2, 0}};
double b[10] = {1, 0.5, 0.4, 0.3, 0};
double num[10][10];
double A, B, A0, B0;
int main() {
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 5; j++) {
      cin >> num[i][j];
      A0 += num[i][j] * a[i][j];
      A += num[i][j] * a[i][0];
    }
  }
  for (int i = 0; i < 5; i++) {
    B0 += num[3][i] * b[i];
    B += num[3][i] * b[0];
  }
  cout << fixed << setprecision(9) << A0 / A * 100 + B0 / B << endl;
  return 0;
}

三、题目分析及解法(基础题)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值