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);
}
posted @ 2022-08-18 15:59  Sakana~  阅读(159)  评论(0编辑  收藏  举报