2022牛客多校(加赛)题解 EHJM
2022牛客多校(加赛)题解 EHJM
https://ac.nowcoder.com/acm/contest/38727#question
大胆猜结论
E - Everyone is bot
题意:有 \(n\) 个人参与复读,第 \(i\) 个人在第 \(j\) 回合复读会获得 \(a_{i,j}\) 的值。每个人可以选择复读也可以选择不复读,倒数第 \(k\) 个复读的人会被惩罚。如果没人复读了,则复读中止。
分析:如果一个人认为他有可能落入后 \(k\) 个的范围内,那么就会有一定几率被惩罚,所以一定不会选择复读,因此答案为输出 \(n\,mod k\) 的对角线
#include <bits/stdc++.h>
using namespace std;
int main () {
int n, k;
scanf ("%d%d", &n, &k);
int cnt = n % k;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
int x;
scanf ("%d", &x);
if (i == j){
if (cnt > 0) {
printf ("%d ", x);
cnt--;
}
else printf ("0 ");
}
}
}
H - Here is an Easy Problem of Zero-chan
题意:根为1,询问 \(q\)次,每次给 \(x\), 求的后缀0的个数
分析:不难发现因子2和5会构成后缀0,所以要与处理一下子树中的这两个因子数,写两个 \(dfs\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 5, M = N*2;
//int h[N], e[M], ne[M], idx;
int n, q;
int sz[N], fa[N]; //子树大小
int cnt2[N], cnt5[N], f2[N], f5[N];
vector <int> e[N];
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
void pre () {
for (int i = 1; i <= n; i++) {
int x = i;
while (x % 2 == 0) cnt2[i] ++, x /= 2;
while (x % 5 == 0) cnt5[i] ++, x /= 5;
}
}
void dfs (int u, int f){
sz[u] = 1;
fa[u] = f;
for(auto v : e[u]){
if(v == f) continue;
dfs(v, u);
sz[u] += sz[v];
}
}
void dfs2 (int u, int f, int c2, int c5) {
f2[u] = c2 + sz[u]*cnt2[u];
f5[u] = c5 + sz[u]*cnt5[u];
for (auto v : e[u]) {
if (v == f) continue;
dfs2 (v, u, f2[u]-sz[v]*cnt2[u], f5[u]-sz[v]*cnt5[u]);
}
}
signed main () {
//memset (h, -1, sizeof h);
n = read (), q = read ();
pre();
for (int i = 1; i < n; i++) {
int a, b;
a = read (), b = read ();
e[a].push_back (b), e[b].push_back (a);
}
dfs (1, 0);
dfs2(1, 0, 0, 0);
//for (int i = 1; i <= n; i++) cout << sz[i] << endl;
while (q --) {
int x;
x = read ();
cout << min (f2[x], f5[x]) << endl;
}
}
//有多少个后缀0
//离线LCA
//子树size*2/5因数个数
J - Jellyfish and its dream
题意:\(a_i\) 只能为 \(0,1,2\), 每次可以把 \((a_i+1)\%3==a_{(i+1)\%n}\)的 \(a_i\) 变为 \((a_i+1)\%3\),问能否通过若干次这样的操作使得所有的数字相等
分析:不难发现如果出现 \(01,12,20\) 这三种情况,就可以实现转化,即视为连一条边。
一条边可以化同两个点,且:
这样子也能保证周围的点也能变为相同,所以如果边数 \(\geq \frac n2\),就能达到目的
(注🐖:本作法做法并不严谨,因为我不会证明)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
//int a[N*2], n;
bool check (int a, int b) {
if (a == 0 && b == 1) return true;
if (a == 1 && b == 2) return true;
if (a == 2 && b == 0) return true;
return false;
}
void solve () {
int n;
scanf ("%d", &n);
vector <int> v;
for (int i = 0; i < n; i++) {
int x;
scanf ("%d", &x);
if (v.empty()) v.push_back (x);
else if (x != v.back()) v.push_back (x);
}
n = v.size();
bool suc = false;
if (n <= 2) printf ("Yes\n");
else {
//可连的边数>=n/2
int cnt = 0;
for (int i = 1; i < n; i++) {
if (check (v[i-1], v[i])) cnt++;
}
if (check (v[n-1], v[0])) cnt++;
if (cnt >= n/2) printf ("Yes\n");
else printf ("No\n");
}
}
int main () {
int t;
scanf ("%d", &t);
while (t --) {
solve ();
}
}
//01 12 20
//可连的边数>=n/2
//看所连边覆盖的点数是否==n
//出现012??
M - Maimai DX 2077
签到题,模拟即可,注意是全部加起来再求最终值
#include <bits/stdc++.h>
using namespace std;
double w[5][5] = {{1,1,0.8,0.5,0}, {2,2,1.6,1,0}, {3,3,2.4,1.5,0}, {5,5,2.5,2,0}, {1,0.5,0.4,0.3,0}};
int main () {
double sum = 0;
double A = 0, A0 = 0, B = 0, B0 = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 5; j++) {
int x; scanf ("%d", &x);
A += w[i][0]*x, A0 += w[i][j]*x;
if (i == 3) B += w[4][0]*x, B0 += w[4][j]*x;
}
}
sum += 1.0*A0/A, sum += 0.01*B0/B;
sum *= 100;
printf ("%.8lf", sum);
}