Sept questions pour le concours de formation ouvert du club ACM de l'Université du pétrole de Chine (terminé)

table des matières

Question A: dessin sciorz

Question B: Kuikui envoie une enveloppe rouge

Question C: Concernant ma réincarnation et devenir un slime

Question D: Grands nombres

Problème E: Ktree

Question F: Sommation

Question G: Dessin de Kuikui

Question H: qiqi et sciorz

Question I: Zonage

Question J: Allez 2020

Problème K: problème mathématique


Question A: dessin sciorz

1. L'idée principale

Trouvez la triangulation optimale de la coque convexe, la fonction de poids trigonométrique est w (i, j, k) = a [i] * a [j] * a [k].

2. Analyse:

Questions nues directement

Xiao Tucao: Ces 100 ensembles de données sont faux ...

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e2;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int a[M + 5];
ll dp[M + 5][M + 5];

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        memset(dp, 0, sizeof(dp));
        for(int len = 3; len <= n; ++len)
        {
            for(int l = 1; l + len - 1 <= n; ++l)
            {
                int r = l + len - 1;
                for(int k = l + 1; k <= r - 1; ++k)
                {
                    dp[l][r] = max(dp[l][r], dp[l][k] + dp[k][r] + 1ll * a[l] * a[k] * a[r]);
                }
            }
        }
        printf("Case #%d: %lld\n", ca, dp[1][n]);
    }
    return 0;
}

Question B: Kuikui envoie une enveloppe rouge

1. L'idée principale du sujet:

Il y a n personnes et chacune a deux attributs v [i], t [i].

n les gens arrivent dans un certain ordre, le coût de la i-ième personne est v [s [i]] * (t [s [1]] + t [s [2]] + ... + t [s [i]] ).

Trouvez le coût minimum de n personnes.

2. Analyse:

Simple et gourmande, la méthode d'échange impérative peut en prouver l'exactitude.

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e5;
const ll inf = 0x3f3f3f3f3f3f3f3f;

struct node
{
    int v, t;
}s[M + 5];

bool cmp(node a, node b)
{
    return a.t * b.v < a.v * b.t;
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d %d", &s[i].v, &s[i].t);
    }
    sort(s + 1, s + n + 1, cmp);
    int t = 0;
    ll ans = 0;
    for(int i = 1; i <= n; ++i)
    {
        t += s[i].t;
        ans += 1ll * t * s[i].v;
    }
    printf("%lld\n", ans);
    return 0;
}

Question C: Concernant ma réincarnation et devenir un slime

1. L'idée principale du sujet:

Une sculpture de sable veut manger des excréments. Le premier jour, ils peuvent manger à volonté mais ne peuvent pas tous les manger. La quantité de matières fécales le i-ième jour doit être un multiple entier de 2 à 9 le i-1er jour et elle doit être mangée exactement le dernier jour.

Cherchez le moins de jours à manger de la merde.

2. Analyse:

Supposons que vous mangiez x le premier jour et que vous mangiez une [i] fois le i-1ème jour le i-ème jour.

s = x + xa [1] + xa [1] a [2] + ... + xa [1] a [2] .. a [n-1]

s = x (1 + a [1] + a [1] a [2] + ... + a [1] a [2] a [n-1])

s = x (1 + a [1] (1 + a [2] + ... + a [2] ... a [n-1]))

La recherche violente est terminée ~

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;

int dfs(int s)
{
    if(s >= 2 && s <= 9)    return 1;
    int ans = inf;
    for(int i = 2; i <= 9; ++i)
    {
        if(s % i == 0)
        {
            ans = min(ans, dfs(s / i - 1) + 1);
        }
    }
    return ans;
}

int main()
{
    int s, ans = inf;
    scanf("%d", &s);
    for(int i = 1; 1ll * i * i <= s; ++i)
    {
        if(s % i == 0)
        {
            ans = min(ans, dfs(s / i - 1) + 1);
            if(i != s / i)  ans = min(ans, dfs(i - 1) + 1);
        }
    }
    printf("%d\n", ans == inf ? -1 : ans);
    return 0;
}

Question D: Grands nombres

1. L'idée principale du sujet:

Trouvez la section de boucle minimale de la chaîne, il n'y a pas de sortie -1.

2. Analyse:

Énumérer le diviseur de la longueur n, vérifier la force brute.

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e6;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int n;
string s;
vector <int> fac;

bool check(int l)
{
    for(int i = 0; i + l - 1 < n; i += l)
    {
        if(s.substr(0, l) != s.substr(i, l))    return 0;
    }
    return 1;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> s;
    n = s.size();
    for(int i = 1; 1ll * i * i <= n; ++i)
    {
        if(n % i == 0)
        {
            fac.push_back(i);
            if(i != n / i)  fac.push_back(n / i);
        }
    }
    sort(fac.begin(), fac.end());
    for(auto x: fac)
    {
        if(x != n && check(x))
        {
            cout << s.substr(0, x) << endl;
            return 0;
        }
    }
    cout << -1 << endl;
    return 0;
}

Problème E: Ktree

1. L'idée principale du sujet:

Étant donné un arbre et la somme de tous les poids d'arête, vous permet d'affecter des poids à chaque arête afin que le diamètre de l'arbre soit le plus petit.

Trouvez le diamètre minimum de l'arbre.

2. Analyse:

Puisque le diamètre doit être le chemin reliant les deux nœuds feuilles, une stratégie optimale simple et gourmande peut être obtenue pour répartir également la somme de poids pour chaque nœud feuille.

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

const int M = (int)1e5;

int de[M + 5];

int main()
{
    int n, s;
    scanf("%d %d", &n, &s);
    for(int i = 0, u, v; i < n - 1; ++i)
    {
        scanf("%d %d", &u, &v);
        de[u]++, de[v]++;
    }
    int cnt = 0;
    for(int i = 1; i <= n; ++i) cnt += (de[i] == 1);
    printf("%.2f\n", 2.0 * s / cnt);
    return 0;
}

Question F: Sommation

1. L'idée principale du sujet:

Étant donné la matrice A d'ordre n, trouvez A + A ^ 2 + ... + A ^ m

2. Analyse:

Construisez la matrice suivante

B = \ begin {bmatrix} A & A \\ 0 & E \ end {bmatrix}

Disponible:B ^ m = \ begin {bmatrix} A ^ m & A + A ^ 2 + ... + A ^ m \\ 0 & E \ end {bmatrix}

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int mod = (int)1e9 + 7;

int n, m, t;
struct Matrix
{
    int mat[60][60];
}B;

Matrix mul(Matrix A, Matrix B)
{
    Matrix C;
    memset(C.mat, 0, sizeof(C.mat));
    for(int i = 0; i < t; ++i)
    {
        for(int j = 0; j < t; ++j)
        {
            for(int k = 0; k < t; ++k)
            {
                C.mat[i][j] = (C.mat[i][j] + 1ll * A.mat[i][k] * B.mat[k][j]) % mod;
            }
        }
    }
    return C;
}

Matrix quick(Matrix A, int b)
{
    Matrix Sum = A;
    --b;
    while(b)
    {
        if(b & 1)   Sum = mul(Sum, A);
        A = mul(A, A);
        b >>= 1;
    }
    return Sum;
}

int main()
{
    scanf("%d %d", &n, &m);
    t = n * 2;
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
        {
            scanf("%d", &B.mat[i][j]);
            B.mat[i][j + n] = B.mat[i][j] %= mod;
            B.mat[i + n][j + n] = (i == j);
        }
    }
    B = quick(B, m);
    for(int i = 0; i < n; ++i)
    {
        for(int j = n; j < t; ++j)
            printf("%d%c", B.mat[i][j], j == t - 1 ? '\n' : ' ');
    }
    return 0;
}

Question G: Dessin de Kuikui

1. L'idée principale du sujet:

Pour la matrice de n * m, les grilles initiales sont toutes blanches, q opérations, chaque opération sélectionne le segment de ligne parallèle à l'axe x ou à l'axe y et le teint en noir, trouvez le nombre de blocs connectés de la grille blanche après chaque opération.

2. Analyse:

Effectuez d'abord les opérations q et enregistrez le nombre de fois (i, j) les points sont couverts.

Parcourez ensuite la matrice, trouvez une grille blanche, recherchez des grilles blanches autour d'elle et recherchez des blocs connectés à marquer.

Puis annulez les opérations q à tour de rôle, les opérations sont similaires à celles ci-dessus.

Voir le code pour plus de détails.

3. Mise en œuvre du code:

#include <cstdio>
using namespace std;

const int M = (int)1e3;
const int N = (int)1e4;

int n, m, q, cnt;
int fa[M * M + 5];
int st[N + 5], top;
int c[M + 5][M + 5];
int x1[N + 5], y1[N + 5];
int x2[N + 5], y2[N + 5];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};

int tofind(int x)
{
    if(x == fa[x])  return x;
    return fa[x] = tofind(fa[x]);
}

void work(int x, int y)
{
    int xx, yy, u, v;
    for(int i = 0; i < 4; ++i)
    {
        xx = x + dx[i];
        yy = y + dy[i];
        if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && !c[xx][yy])
        {
            u = (x - 1) * m + y;
            v = (xx - 1) * m + yy;
            u = tofind(u), v = tofind(v);
            if(u != v)
            {
                --cnt;
                fa[u] = v;
            }
        }
    }
}

int main()
{
    scanf("%d %d %d", &n, &m, &q);
    for(int i = 1; i <= q; ++i)
    {
        scanf("%d %d %d %d", &x1[i], &y1[i], &x2[i], &y2[i]);
        for(int x = x1[i]; x <= x2[i]; ++x)
        {
            for(int y = y1[i]; y <= y2[i]; ++y)
            {
                c[x][y]++;
            }
        }
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            fa[(i - 1) * m + j] = (i - 1) * m + j;
        }
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            if(!c[i][j])
            {
                ++cnt;
                work(i, j);
            }
        }
    }
    for(int i = q; i >= 1; --i)
    {
        st[++top] = cnt;
        for(int x = x1[i]; x <= x2[i]; ++x)
        {
            for(int y = y1[i]; y <= y2[i]; ++y)
            {
                --c[x][y];
            }
        }
        for(int x = x1[i]; x <= x2[i]; ++x)
        {
            for(int y = y1[i]; y <= y2[i]; ++y)
            {
                if(!c[x][y])
                {
                    ++cnt;
                    work(x, y);
                }
            }
        }
    }
    while(top)  printf("%d\n", st[top--]);
    return 0;
}

Question H: qiqi et sciorz

1. L'idée principale du sujet:

Jeu de K fois.

2. Analyse (copiez la solution du problème) :

3. Mise en œuvre du code

#include <bits/stdc++.h>
using namespace std;

const int M = (int)1e5;

int a[M + 5];
int b[M + 5];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, k;
        scanf("%d %d", &n, &k);
        int i = 0, j = 0;
        a[i] = b[j] = 1;
        while(a[i] < n)
        {
            ++i;
            a[i] = b[i - 1] + 1;
            while(k * a[j + 1] < a[i])  ++j;
            if(k * a[j] < a[i]) b[i] = a[i] + b[j];
            else                b[i] = a[i];
        }
        if(a[i] == n)
        {
            printf("qiqi lose\n");
            continue;
        }
        int ans;
        while(n)
        {
            if(n >= a[i])
            {
                n -= a[i];
                ans = a[i];
            }
            --i;
        }
        printf("%d\n", ans);
    }
    return 0;
}

Question I: Zonage

1. L'idée principale du sujet:

Étant donné n points en coordonnées tridimensionnelles, chaque point a un poids v.

Définissez deux points comme le même système si et seulement si les deux points sont adjacents l'un à l'autre et que la valeur absolue de la différence de poids ne dépasse pas m.

La relation est transitive. Combien de lignes y a-t-il au total?

2. Analyse:

N ^ 2 énumération + recherche d'union

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e3;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int x[M + 5];
int y[M + 5];
int z[M + 5];
int v[M + 5];
int fa[M + 5];

ll dist(int i, int j)
{
    ll dis = 0;
    dis += (ll)abs(x[i] - x[j]);
    dis += (ll)abs(y[i] - y[j]);
    dis += (ll)abs(z[i] - z[j]);
    return dis;
}

int cal(int i, int j)
{
    return (int)abs(v[i] - v[j]);
}

int tofind(int x)
{
    if(x == fa[x])  return x;
    return fa[x] = tofind(fa[x]);
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
        fa[i] = i;
        scanf("%d %d %d %d", &x[i], &y[i], &z[i], &v[i]);
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = i + 1; j <= n; ++j)
        {
            if(dist(i, j) <= 1 && cal(i, j) <= m)
            {
                int u = tofind(i);
                int v = tofind(j);
                if(u != v)
                {
                    fa[u] = v;
                }
            }
        }
    }
    int cnt = 0;
    for(int i = 1; i <= n; ++i) cnt += (fa[i] == i);
    printf("%d\n", cnt);
    return 0;
}

Question J: Allez 2020

1. L'idée principale du sujet:

2. Analyse:

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e3;
const int N = (int)2019;

int n; ll p;

bool is_prime[N + 5];
int cnt, prime[N + 5];

int tot;
struct node
{
    int p, c;
}fac[M + 5];
ll f[M + 5];

ll g[M + 5];

void get_prime()
{
    memset(is_prime, 1, sizeof(is_prime));
    is_prime[0] = is_prime[1] = 0;
    for(int i = 2; i <= N; ++i)
    {
        if(is_prime[i]) prime[++cnt] = i;
        for(int j = 1; j <= cnt && i * prime[j] <= N; ++j)
        {
            is_prime[i * prime[j]] = 0;
            if(i % prime[j] == 0)   break;
        }
    }
}

ll mul(ll a, ll b)
{
    ll sum = 0;
    while(b)
    {
        if(b & 1)   sum = (sum + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return sum;
}

void get_fac()
{
    for(int i = 1; i <= cnt && prime[i] <= N; ++i)
    {
        int cnt = 0;
        int p = prime[i];
        while(p <= N)
        {
            cnt += N / p;
            if(1ll * p * prime[i] > N)  break;
            p *= prime[i];
        }
        if(cnt) fac[++tot].p = prime[i], fac[tot].c = cnt;
    }
}

void get_f()
{
    get_prime();
    get_fac();
    for(int i = 1; i <= n; ++i)
    {
        f[i] = 1;
        for(int j = 1; j <= tot; ++j)
        {
            f[i] = mul(f[i], i * fac[j].c + 1);
        }
    }
}

ll quick(ll a, ll b)
{
    ll sum = 1;
    while(b)
    {
        if(b & 1)   sum = mul(sum, a);
        a = mul(a, a);
        b >>= 1;
    }
    return sum;
}

ll inv(int a)
{
    return quick(a, p - 2);
}

ll get_sum(ll a, int b)
{
    return mul(a, inv(b));
}

void get_g()
{
    ll a = 673, b = 3;
    for(int i = 1; i <= n; ++i)
    {
        a = mul(a, 673), b = mul(b, 3);
        g[i] = mul(get_sum(a - 1, 673 - 1), get_sum(b - 1, 3 - 1));
    }
}

int main()
{
    scanf("%d %lld", &n, &p);
    get_f();
    get_g();
    ll ans = 0;
    for(int i = 1; i <= n; ++i) ans = (ans + mul(f[i], g[i])) % p;
    printf("%lld\n", ans);
    return 0;
}

Problème K: problème mathématique

1. L'idée principale du sujet:

Donnez un entier g, puis T groupes de requêtes, chaque groupe donne n et m.

Trouvez combien de paires (i, j) sont divisibles par g  C _ {\; j} ^ {\;  je}, où 0 ≤ i ≤ n, 0 ≤ j ≤ min (i, m).

2. Analyse:

O (2000 * 2000) prétraite toutes les combinaisons et leur somme de paires de préfixes, requête O (1).

3. Mise en œuvre du code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)2e3;
const int mod = (int)1e9 + 7;

int T, g;
int c[M + 5][M + 5];
int s[M + 5][M + 5];

void init()
{
    for(int i = 1; i <= M + 1; ++i)
    {
        c[i][1] = 1 % g;
        for(int j = 2; j <= i; ++j)
        {
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % g;
        }
    }
    for(int i = 1; i <= M + 1; ++i)
    {
        for(int j = 1; j <= i; ++j)
        {
            c[i][j] = !c[i][j];
        }
    }
    for(int i = 1; i <= M + 1; ++i)
    {
        for(int j = 1; j <= M + 1; ++j)
        {
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + c[i][j];
        }
    }
}

int main()
{
    scanf("%d %d", &T, &g);
    init();
    while(T--)
    {
        int n, m;
        scanf("%d %d", &n, &m);
        printf("%d\n", s[n + 1][m + 1]);
    }
    return 0;
}

 

Je suppose que tu aimes

Origine blog.csdn.net/The___Flash/article/details/104748544
conseillé
Classement