gym-102452 香港区域赛部分题解

gym-102452 香港区域赛部分题解

本人水平有限只会这几道题

B - Binary Tree

题意:给出一颗二叉树,Alice和Bob轮流删除子树,子树要求是完全二叉树。
在这里想了很久,什么模拟都来了,最后想了一下,好像退了几个样例找到了结论。
根据n的奇偶判答案

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int maxn = 200005;
 
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T, n;
    cin >> T;
    while (T--) {
        cin >> n;
        int u, v;
        for (int i = 1; i < n; i++) {
            cin >> u >> v;
        }
        if (n & 1) puts("Alice");
        else puts("Bob");
    }
    return 0;
}

D - Defining Labels

这道题有点像进制转换,但有不完全是,注意细节,应该是减去前面的次方,在进行进制转换。

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int maxn = 200005;
 
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        ll k, x;
        cin >> k >> x;
        if (x == 1) {
            cout << 10 - k << endl;
            continue;
        }
        ll s = k;
        int count = 1;
        while (x) {
            if (x - s <= 0) break;
            x -= s;
            s *= k;
            count++;
        }
        int t = 10 - k, st[110], cnt = 0;
        x--;
        while (x) {
            st[++cnt] = x % k;
            x /= k;
        }
        for (int i = 0; i < count - cnt; i++)
            cout << t;
        for (int i = cnt; i >= 1; i--) {
            cout << st[i] + t;
        }
        cout << endl;
    }
    return 0;
}

G - Game Design

这道题就有点意思了,首先1和2 容易构造。
我拿到这道题马上就想到了,二进制拆分,因为有乘法关系,就想着偶数n/2 2,,奇数基础上加一,但不过总是WA6,不知道为啥。后来发现减一也不影响,就吧奇数合到了偶数那边。我估计正解应该是分解因子吧。

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int maxn = 200005;
ll k, c[maxn], fa[maxn];
int ans[maxn], mx = 1;
 
ll dfs(ll k, int id) {
    if (k == 1) {
        return c[id] = 1;;
    }
    if (k == 2) {
        c[id] = 1;
        fa[++mx] = id;
        c[mx] = 1;
        return 1;
    }
    if (k & 1) {
        k -= 1;
        if (k == 2) {
            fa[++mx] = id;
            c[id] += dfs(2, mx);
        } else {
            fa[++mx] = id;
            c[id] += dfs(k / 2, mx);
            fa[++mx] = id;
            c[id] += dfs(2, mx);
        }
    } else {
        fa[++mx] = id;
        c[id] += dfs(k - 1, mx);
    }
    return c[id];
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> k;
    if (k == 1) {
        cout << 2 << endl;
        cout << 1 << endl;
        cout << "1 2" << endl;
        return 0;
    }
    dfs(k, 1);
    cout << mx << endl;
    for (int i = 2; i <= mx; i++) {
        if (i == mx) cout << fa[i] << endl;
        else cout << fa[i] << " ";
    }
    for (int i = 1; i <= mx; i++) {
        if (i == mx) cout << c[i] << endl;
        else cout << c[i] << " ";
    }
    return 0;
}

J - Junior Mathematician

这道题就是要你求L到R的这个
x = f ( x ) ( m o d m ) x=f(x) (mod m) x=f(x)(modm) 的数量
很明显数位DP
d p [ i ] [ j ] [ k ] 表 示 i 位 当 前 ∑ t f ( x , t )   ( m o d   m ) = j , ( f ( x ) − x )   ( m o d   m ) = k dp[i][j][k]表示i位当前\sum_{t} f(x,t)  (mod  m)=j,(f(x)-x)  (mod m)=k dp[i][j][k]itf(x,t) (mod m)=j,(f(x)x) (mod m)=k
d p [ i ] [ j ] [ k ] 转 移 d p [ i + 1 ] [ j + p o s [ i ] ] [ k + j ∗ p o s [ i ] − p o s [ i ] ∗ 1 0 k − i + 1 ] dp[i][j][k]转移dp[i+1][j+pos[i]][k+j*pos[i]-pos[i]*10^{k-i+1}] dp[i][j][k]dp[i+1][j+pos[i]][k+jpos[i]pos[i]10ki+1]
直接dp就可以了。注意比较卡常数。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 5010;
char s1[maxn], s2[maxn];
const ll mod = 1000000000 + 7;
int p[maxn], a[maxn], md;
ll dp[maxn][66][66];

ll dfs(int pos, int pre1, int pre2, bool limit) {
    if (pos < 1) return !pre2;
    if (!limit && dp[pos][pre1][pre2] != -1) return dp[pos][pre1][pre2];
    ll ans = 0;
    int up = (limit ? a[pos] : 9);
    for (int i = 0; i <= up; i++) {
        ans += dfs(pos - 1, (pre1 + i) % md, ((pre2 + i * pre1 - i * p[pos - 1]) % md + md) % md,
                   i == up && limit);
    }
    ans %= mod;
    if (!limit) dp[pos][pre1][pre2] = ans;
    return ans;
}

ll solve(char s[], int len) {
    for (int i = 1; i <= len; i++)
        for (int j = 0; j <= md; j++)
            for (int k = 0; k <= md; k++)
                dp[i][j][k] = -1;
//    memset(dp, -1, sizeof(dp));
    for (int i = 1; i <= len; i++) {
        a[i] = s[len - i + 1] - '0';
    }
    return dfs(len, 0, 0, true);
}

int main() {
//    ios::sync_with_stdio(false);
//    cin.tie(0), cout.tie(0);
    p[0] = 1;
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%s %s %d", s1 + 1, s2 + 1, &md);
        int n = strlen(s2 + 1);
        int m = strlen(s1 + 1);
        for (int i = 1; i <= n; i++)
            p[i] = p[i - 1] * 10 % md;
        s1[m]--;
        for (int i = m; i >= 1; i--) {
            if (s1[i] - '0' < 0) s1[i] += 10, s1[i - 1]--;
            else break;
        }
//        cout << (solve(s2) - solve(s1) + mod) % mod << endl;
        printf("%lld\n", (solve(s2, n) - solve(s1, m) + mod) % mod);
    }

    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值