HHKB Programming Contest 2020 补题记录(D题投影,E题预处理节省时间)

补题链接:Here

A - Keyboard

签到,S 为 Y 则输出大写 T,不然则原样输出 T

int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    char s, t;
    cin >> s >> t;
    cout << (char)(s == 'Y' ? toupper(t) : t);
    return 0;
}

B - Futon

对于每个.我们只考虑向右和向下能不能放置即可,这样计数便不会重复。

int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int n, m;
    cin >> n >> m;
    vector<string> s(n);
    for (auto &c : s) cin >> c;
    int cnt = 0;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            if (s[i][j] == '.') {
                if (i + 1 < n && s[i + 1][j] == '.') cnt++;
                if (j + 1 < m && s[i][j + 1] == '.') cnt++;
            }
    cout << cnt << "\n";
    return 0;
}

C - Neq Min

维护一个a[]和当前答案t,来一个数就添加一个数,答案输出当前 t 即可。

int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int n, t = 0;
    cin >> n;
    int a[200010] = {0};
    for (int i = 1, x; i <= n; ++i) {
        cin >> x;
        a[x] = 1;
        while (a[t]) t++;
        cout << t << "\n";
    }
    return 0;
}

D - Squares

大佬题解另一位大佬的题解
方法非常巧妙投影,举体解释可以参考上述题解。

如果两个正方形在二维平面内相交,那么将两个正方形投影到x轴上会出现两条线段,这两条线段一定相交,同理投影到y轴也一定相交。

由上述性质不难看出我们只需要计算两条线段相交或者不相交的方案数,这个是非常容易的可以参考上述题解的方法。

那么最后答案一定是:X轴不相交的方案数(Y轴随意)+ X轴相交但是Y不相交的方案数
或者是:总方案数− X 轴相交且Y轴相交的方案数

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
using ll      = long long;
int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int T = 1;
    ll N, A, B;
    for (cin >> T; T--;) {
        cin >> N >> A >> B;
        ll C = N - A + 1, D = N - B + 1, E = N - A - B;
        ll f   = E < 0 ? 0 : (E + 2) * (E + 1) / 2 % mod;
        ll ans = 4 * f * (C * D % mod - f) % mod;
        cout << (ans + mod) % mod << '\n';
    }
    return 0;
}

D题非常数学,这个投影的方法还是非常巧妙的,学习了

E - Lamps

这道题TLE了,然后虚拟赛后才发现做个预处理就能A了

不难想到要单独考虑每一个.点最答案的贡献

不妨设.的数量是cnt
如果 g[i][j]=='.'那么考虑什么情况下对答案有贡献?如果能够点亮该点的点数量是 w 那么最终这个点对答案的贡献即是 \((2^w-1)*2^{cnt-w}\) ,只要能点亮该点的一个点点亮即可,不能控制该点的随意。

然后预处理每个点能由多少个点点亮即可。

#include <bits/stdc++.h>
using namespace std;
using ll     = long long;
const int N  = 2e3 + 10;
const ll mod = 1e9 + 7;
char g[N][N];
int n, m, w[N][N];
ll base[N * N];
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> g[i] + 1;

    int cnt = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) cnt += (int)g[i][j] == '.';
    base[0] = 1;
    for (int i = 1; i <= cnt; i++) base[i] = base[i - 1] * 2 % mod;
    // 预处理数组
    for (int i = 1; i <= n; i++) {
        int j = 1;
        while (j <= m) {
            while (g[i][j] == '#') j++;
            int now = 1, k = 1;
            while (j + k <= m && g[i][j + k] == '.') now++, k++;
            for (int p = j; p < j + k; p++) w[i][p] += now;
            j = j + k;
        }
    }
    for (int i = 1; i <= m; i++) {
        int j = 1;
        while (j <= n) {
            while (g[j][i] == '#') j++;
            int now = 1, k = 1;
            while (j + k <= n && g[j + k][i] == '.') now++, k++;
            for (int p = j; p < j + k; p++) w[p][i] += now;
            j = j + k;
        }
    }
    // 计算答案
    ll res = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (g[i][j] == '#') continue;
            int now = w[i][j] - 1;
            res     = (res + (base[now] - 1) * base[cnt - now] % mod) % mod;
        }
    }
    cout << (ll)(res + mod) % mod << '\n';
    return 0;
}

F题随缘补...HHKB Programming Contest 2020

上一篇:GBDT、XGBoost、LightGBM的区别和联系


下一篇:Atcoder Regular Contest 117 D - Miracle Tree(分析性质+构造)