SMU Summer 2024 Contest Round 7

Make Equal With Mod

思路:这是一道思维题,我们贪心来看,一定是从最大的开始操作,最大的和自己取模不会影响其他数,但是如果既有零也有一定不行,所以只要没有一,肯定可以操作完成,有一的话就只能全部变为一,那么就从最大的开始和比自己小一的数取模,然后比自己小一的数存在,那也一定不行

void solve() {
    int n; cin >> n;
    map<int, int> mp;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        mp[a[i]] ++;
    }
    if (mp.size() == 1) {
        cout << "YES" << '\n';
        return ;
    }
    if (mp.count(1)) {
        if (mp.count(0)) {
            cout << "NO" << '\n';
            return ;
        }
        for (int i = 1; i <= n; i ++) {
            if (a[i] <= 1) continue;
            if (mp.count(a[i] - 1)) {
                cout << "NO" << '\n';
                return ;
            }
        }
        cout << "YES" << '\n';
    } else cout << "YES" << '\n';
}

Game on Ranges

思路:所有数据保证不超过 1000 1000 1000,直接 n 2 n^2 n2暴力就行,区间从小到大

void solve() {
    int n; cin >> n;
    vector<array<int, 2>> seg, t;
    for (int i = 0; i < n; i ++) {
        int l, r; cin >> l >> r;
        seg.push_back({l, r});
    }
    t = seg;
    map<int, int> mp;
    sort(seg.begin(), seg.end(), [&](array<int, 2> a, array<int, 2> b) {
        return a[1] - a[0] < b[1] - b[0];
    });
    map<array<int, 2>, int> ans;
    for (auto [l, r] : seg) {
        for (int i = l; i <= r; i ++) {
            if (!mp.count(i)) {
                mp[i] ++;
                ans[ {l, r}] = i;
                break;
            }
        }
    }
    for (auto [l, r] : t) {
        cout << l << ' ' << r << ' ';
        cout << ans[ {l, r}] << '\n';
    }
    cout << '\n';
}

Buy an Integer

思路:枚举 d ( N ) d(N) d(N)的值,二分 N N N即可

int get(int x) {
    int cnt = 0;
    while (x) {
        cnt ++;
        x /= 10;
    }
    return cnt;
}

void solve() {
    int a, b, x; cin >> a >> b >> x;
    int ans = 0;
    int p = 1;
    for (int i = 1; i <= 10; i ++) {
        if (i >= 2) p *= 10;
        int y = x - b * i;
        int l = p, r = 1e9, res = -1;
        while (l <= r) {
            int mid = l + r >> 1;
            if (get(mid) == i && a * mid + b * i <= x) l = mid + 1, res = mid;
            else r = mid - 1;
        }
        ans = max(ans, res);
    }
    cout << ans << '\n';
}

String Formation

思路:用两个数组模拟来维护加在两边的字符就行行

void solve() {
    string s; cin >> s;
    int Q; cin >> Q;
    vector<char> f, b;
    int t = 1;
    while (Q --) {
        int op; cin >> op;
        if (op == 1) {
            t ^= 1;
        } else {
            int x; char c; cin >> x >> c;
            if (t == 1) {
                if (x == 1) f.push_back(c);
                else b.push_back(c);
            } else {
                if (x == 1) b.push_back(c);
                else f.push_back(c);
            }
        }
    }
    if (t == 1) {
        reverse(f.begin(), f.end());
        for (auto i : f) cout << i;
        for (auto i : s) cout << i;
        for (auto i : b) cout << i;
    } else {
        reverse(b.begin(), b.end());
        for (auto i : b) cout << i;
        reverse(s.begin(), s.end());
        for (auto i : s) cout << i;
        for (auto i : f) cout << i;
    }
}

Bouquet

思路:组合数的题,那总的方案数减去选 a a a和选 b b b的方案数就是答案,因为保证 a a a b b b不超过 2 e 5 2e5 2e5,所以计算 C ( n , a ) C(n, a) C(n,a) C ( n , b ) C(n, b) C(n,b)的时候化简一下公式就行,不知道为什么 l u c a s lucas lucas也可以过

int ksm(int a, int k) {
    int res = 1;
    while (k) {
        if (k & 1) res = (res * a) % mod;
        a = (a * a) % mod;
        k >>= 1;
    }
    return res;
}

int C(int a, int b) {
    int ans = 1, inv = 1;
    for (int i = 1; i <= b; i ++) {
        inv = inv * ksm(i, mod - 2) % mod;
    }
    for (int i = a - b + 1; i <= a; i ++) {
        ans = ans * i % mod;
    }
    return ans * inv % mod;
}

void solve() {
    int a, b, n; cin >> n >> a >> b;
    cout << (((ksm(2, n) - C(n, a) + mod) % mod - C(n, b) + mod) % mod - 1 + mod) % mod << '\n';
}

Permutation

思路:一个不那么典型的状压 d p dp dp d p [ i ] dp[i] dp[i]表示选择数的情况为 i i i的时候的方案数(用一个数字的二进制表示, 0 0 0表示不选这个数, 1 1 1表示选这个数),从选 1 1 1个数一直转移到选 n n n个数,在转移的过程中我们要判断选出来的数是不是符合选这些数量的数的限制条件,符合条件在进行转移,这里的dp[i ^ (1 << (j - 1))] 不选 j j j这个数的方案数

void solve() {
    int n, m; cin >> n >> m;
    map<int, vector<array<int, 2>>> mp;
    for (int i = 1; i <= m; i ++) {
        int x, y, z; cin >> x >> y >> z;
        mp[x].push_back({y, z});
    }
    vector<int> dp(1 << n);
    dp[0] = 1;
    for (int i = 1; i < 1 << n; i ++) {
        vector<int> t;
        int cv = 0, ok = 0;
        for (int j = 0; j < n; j ++) {
            if (i >> j & 1) t.push_back(j + 1), cv ++;
        }
        for (auto [y, z] : mp[cv]) {
            int cnt = 0;
            for (auto j : t) {
                if (j <= y) cnt ++;
                if (cnt > z) ok = 1;
            }
        }
        if (!ok) {
            for (auto j : t) {
                dp[i] += dp[i ^ (1 << j - 1)];
            }
        }
    }
    cout << dp[(1 << n) - 1] << '\n';
}

String Cards

思路:字符串连接起来最小,首先想到自定义排序,但是这样还远远不行,排个序就能过的这个题是选全部的字符串,而这个题是选 k k k个字符串,所以 d p dp dp,设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示在 i − n i-n in这个区间里面选 j j j个字符串行成最小字典序的字符串,这个题有后效性的影响,所以我们倒着往前 d p dp dp

从前往后为什么不对的样例

输入
4 3
bababa
bab
b
b

输出
bababababb
void solve() {
    int n, k; cin >> n >> k;
    vector<string> s(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> s[i];
    }
    sort(s.begin() + 1, s.end(), [&](string a, string b) {
        return a + b < b + a;
    });
    vector<vector<string>> dp(n + 2, vector<string>(n + 2));
    dp[n][1] = s[n];
    for (int i = n - 1; i >= 1; i --) {
        for (int j = 1; j <= n - i + 1; j ++) {
            dp[i][j] = s[i] + dp[i + 1][j - 1];
            if (dp[i + 1][j] != "") dp[i][j] = min(dp[i + 1][j], dp[i][j]);
        }
    }
    cout << dp[1][k] << '\n';
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值