Skip to content

2018 Multi-University Training Contest 8

Contents

A. Character Encoding

题意:

m[0,n-1] 的数去构成 k,求方案数。

思路:

当没有 [0,n-1] 这个条件是答案为 C(k+m-1, m-1)

减去有大于的关于 n 的情况,当有 in 时的种类为 C(k+m-1-i \cdot n,m-1) 个,利用容斥定理可得。

Code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MOD = 998244353;
const int maxn = 1e6 + 10;

ll fac[maxn];
ll inv[maxn];
ll invfac[maxn];

void Init() {
    fac[0] = inv[0] = invfac[0] = 1;
    fac[1] = inv[1] = invfac[1] = 1;
    for (int i = 2; i < maxn; ++i) {
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;
        invfac[i] = invfac[i - 1] * inv[i] % MOD;
    }
}

ll calc(ll n, ll m) {
    if (m > n || m < 0 || n < 0)
        return 0;
    return fac[n] * invfac[m] % MOD * invfac[n - m] % MOD;
}

int n, m, k;

int main() {
    Init();
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d %d %d", &n, &m, &k);
        ll ans = 0;
        for (int i = 0; i <= m; ++i) {
            ll tmp = k - 1ll * i * n + m - 1;
            if (tmp < 0)
                break;
            if (i & 1)
                ans = (ans - calc(m, i) * calc(tmp, m - 1) % MOD + MOD) % MOD;
            else
                ans = (ans + calc(m, i) * calc(tmp, m - 1) % MOD) % MOD;
            //    cout << i << " " << m << " " << calc(m, i);
            //    cout << tmp << " " << m - 1 << " " << calc(tmp, m - 1) << endl;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

B. Pizza Hub

题意:

给出一个三角形,以及一个矩形的宽度,求一个最小的高度使得矩形能够覆盖三角形。

思路:

显然一定有一个点在矩形的顶点,枚举计算即可

Code
#include <bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e2;

int sgn(double x) {
    if (fabs(x) < eps)
        return 0;
    else
        return x > 0 ? 1 : -1;
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) {
        x = _x;
        y = _y;
    }

    void input() {
        scanf("%lf %lf", &x, &y);
    }

    Point operator-(const Point &b) const {
        return Point(x - b.x, y - b.y);
    }

    double operator^(const Point &b) const {
        return x * b.y - y * b.x;
    }

    double distance(Point p) {
        return hypot(x - p.x, y - p.y);
    }

    double len() {
        return hypot(x, y);
    }

    double operator*(const Point &b) const {
        return x * b.x + y * b.y;
    }
} P[maxn];

int w;
double ans;
double area;

void calc(Point a, Point b)  // low high
{
    if (sgn(a * b) < 0)
        return;
    if (sgn(a * a - w * w) <= 0) {
        if (sgn(a ^ b) < 0)
            return;
        if (sgn((a * b) * (a * b) - w * w * (a * a)) > 0)
            return;
        ans = min(ans, (a ^ b) / sqrt(a * a));
    } else {
        double h = sqrt(a * a - w * w);
        double src1 = atan(h / w);
        if (sgn(a ^ b) >= 0) {
            double src2 = acos((a * b) / (sqrt(a * a) * sqrt(b * b)));
            if (sgn(src1 + src2 - PI / 2) > 0)
                return;
            double len1 = sqrt(b * b) * cos(src1 + src2);
            if (sgn(len1 - w) > 0)
                return;
            ans = min(ans, max(h, sqrt(b * b) * sin(src1 + src2)));
        } else {
            double src2 = acos((a * b) / (sqrt(a * a) * sqrt(b * b)));
            if (sgn(src1 - src2) < 0)
                return;
            double len1 = sqrt(b * b) * cos(src1 - src2);
            if (sgn(len1 - w) > 0)
                return;
            ans = min(ans, h);
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        for (int i = 1; i <= 3; ++i) P[i].input();
        //    double a = p[1].distance(p[2]);
        //    double b = p[2].distance(p[3]);
        //    double c = p[3].distance(p[1]);
        //    double p = (a + b + c) / 2.0;
        //    area = sqrt(p * (p - a) * (p - b) * (p - c));
        ans = INF * 1.0;
        scanf("%d", &w);
        calc(P[2] - P[1], P[3] - P[1]);
        calc(P[3] - P[1], P[2] - P[1]);
        calc(P[1] - P[2], P[3] - P[2]);
        calc(P[3] - P[2], P[1] - P[2]);
        calc(P[1] - P[3], P[2] - P[3]);
        calc(P[2] - P[3], P[1] - P[3]);
        for (int i = 1; i <= 3; ++i) P[i].y *= -1.0;
        calc(P[2] - P[1], P[3] - P[1]);
        calc(P[3] - P[1], P[2] - P[1]);
        calc(P[1] - P[2], P[3] - P[2]);
        calc(P[3] - P[2], P[1] - P[2]);
        calc(P[1] - P[3], P[2] - P[3]);
        calc(P[2] - P[3], P[1] - P[3]);
        if (ans >= INF * 1.0)
            puts("impossible");
        else
            printf("%.10f\n", ans);
    }
    return 0;
}

C. City Development

留坑。

D. Parentheses Matrix

题意:

构造一个矩阵,每一行和每一列都会构成一个括号序列,求合法括号序列尽量多。

思路:

分类讨论:

n,m 都是奇数,随便构造。

n,m 有一个奇数 那么答案是那个奇数。

比如 1, 4

()()

两个都是偶数,如果有一个为 2

比如 2,4

((((

))))

如果两个都大于 4

比如 6,6

((((((

()()()

(()())

()()()

(()())

)))))

像这样构造 答案是 n + m - 4

如果 n, m 中有个 4

比如 4,4

(())

()()

(())

()()
Code
#include <bits/stdc++.h>

using namespace std;

const int maxn = 200 + 10;

int n, m;
char str[maxn][maxn];

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d %d", &n, &m);
        //        printf("%d %d\n", n, m);
        if (n % 2 == 1 && m % 2 == 1) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    printf("(");
                }
                printf("\n");
            }
        } else if (n % 2 == 1) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (j & 1)
                        printf("(");
                    else
                        printf(")");
                }
                printf("\n");
            }
        } else if (m % 2 == 1) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (i & 1)
                        printf("(");
                    else
                        printf(")");
                }
                printf("\n");
            }
        } else if (n == 2) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (i & 1)
                        printf("(");
                    else
                        printf(")");
                }
                printf("\n");
            }
        } else if (m == 2) {
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (j & 1)
                        printf("(");
                    else
                        printf(")");
                }
                printf("\n");
            }
        } else if (n == 4) {
            for (int i = 1; i <= m; ++i) printf("(");
            printf("\n");
            for (int i = 1; i <= m; ++i) {
                if (i & 1)
                    printf("(");
                else
                    printf(")");
            }
            printf("\n");
            for (int i = 1; i <= m; ++i) {
                if (i & 1)
                    printf(")");
                else
                    printf("(");
            }
            printf("\n");
            for (int i = 1; i <= m; ++i) printf(")");
            printf("\n");
        } else if (m == 4) {
            for (int i = 1; i <= n; ++i) str[i][1] = '(';
            for (int i = 1; i <= n; ++i) {
                if (i & 1)
                    str[i][2] = '(';
                else
                    str[i][2] = ')';
            }
            for (int i = 1; i <= n; ++i) {
                if (i & 1)
                    str[i][3] = ')';
                else
                    str[i][3] = '(';
            }
            for (int i = 1; i <= n; ++i) str[i][4] = ')';
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    printf("%c", str[i][j]);
                }
                printf("\n");
            }
        } else {
            for (int i = 1; i <= m; ++i) str[1][i] = '(';
            for (int i = 2; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (i & 1) {
                        if (j == 1)
                            str[i][j] = '(';
                        else if (j == m)
                            str[i][j] = ')';
                        else if (j & 1)
                            str[i][j] = ')';
                        else
                            str[i][j] = '(';
                    } else {
                        if (j & 1)
                            str[i][j] = '(';
                        else
                            str[i][j] = ')';
                    }
                }
            }
            for (int i = 1; i <= m; ++i) str[n][i] = ')';
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    printf("%c", str[i][j]);
                }
                printf("\n");
            }
        }
    }
    return 0;
}

E. Magic Square

按题意模拟即可。

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

#define pii pair<int, int>
int t, n;
char G[5][5];

void C(pii a) {
    int x = a.first, y = a.second;
    char tmp[5][5];
    tmp[1][1] = G[x + 1][y];
    tmp[1][2] = G[x][y];
    tmp[2][1] = G[x + 1][y + 1];
    tmp[2][2] = G[x][y + 1];
    for (int i = 1; i <= 2; ++i)
        for (int j = 1; j <= 2; ++j) G[x + i - 1][y + j - 1] = tmp[i][j];
}

void R(pii a) {
    int x = a.first, y = a.second;
    char tmp[5][5];
    tmp[1][1] = G[x][y + 1];
    tmp[1][2] = G[x + 1][y + 1];
    tmp[2][1] = G[x][y];
    tmp[2][2] = G[x + 1][y];
    for (int i = 1; i <= 2; ++i)
        for (int j = 1; j <= 2; ++j) G[x + i - 1][y + j - 1] = tmp[i][j];
}

pii pos[4] = {
        pii(1, 1),
        pii(1, 2),
        pii(2, 1),
        pii(2, 2),
};

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 1; i <= 3; ++i) scanf("%s", G[i] + 1);
        char op;
        int x;
        for (int i = 1; i <= n; ++i) {
            scanf("%d %c", &x, &op);
            if (op == 'C')
                C(pos[x - 1]);
            else
                R(pos[x - 1]);
        }
        for (int i = 1; i <= 3; ++i) printf("%s\n", G[i] + 1);
    }
    return 0;
}

F. Boolean 3-Array

留坑。

G. Card Game

留坑。

H. K-Similar Strings

留坑。

I. Make ZYB Happy

留坑。

J. Taotao Picks Apples

题意:

每次可以改变一个值,求改变之后以第一个数开头的最长上升子序列的长度,改变仅当次有效。

思路:

考虑线段树,维护一个 cnt, 和一个 Max

两个区间合并的时候;

  • 如果 \mbox{左区间的}Max > \mbox{右区间的} Max
  • 那么右区间没有贡献。
  • 否则递归查找贡献。
Code
#include <bits/stdc++.h>
using namespace std;

#define N 100010
int t;
int n, m;
int arr[N];

struct SEG {
    int cnt[N << 2], Max[N << 2];
    void build(int id, int l, int r) {
        cnt[id] = Max[id] = 0;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
    }
    int query(int id, int l, int r, int val) {
        if (l == r)
            return Max[id] > val;
        int mid = (l + r) >> 1;
        if (Max[id] <= val)
            return 0;
        if (Max[id << 1] <= val)
            return query(id << 1 | 1, mid + 1, r, val);
        else
            return cnt[id] - cnt[id << 1] + query(id << 1, l, mid, val);
    }
    void update(int id, int l, int r, int pos, int val) {
        if (l == r) {
            cnt[id] = 1;
            Max[id] = val;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid)
            update(id << 1, l, mid, pos, val);
        else
            update(id << 1 | 1, mid + 1, r, pos, val);
        cnt[id] = cnt[id << 1] + query(id << 1 | 1, mid + 1, r, Max[id << 1]);
        Max[id] = max(Max[id << 1], Max[id << 1 | 1]);
    }
} seg;

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) scanf("%d", arr + i);
        seg.build(1, 1, n);
        for (int i = 1; i <= n; ++i) seg.update(1, 1, n, i, arr[i]);
        for (int i = 1, x, v; i <= m; ++i) {
            scanf("%d%d", &x, &v);
            seg.update(1, 1, n, x, v);
            printf("%d\n", seg.cnt[1]);
            seg.update(1, 1, n, x, arr[x]);
        }
    }
    return 0;
}

K. Pop the Balloons

留坑。

L. From ICPC to ACM

留坑。


Last update: March 29, 2022
Created: March 29, 2022
Back to top