AtCoder Beginner Contest 215(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 215(补题)相关的知识,希望对你有一定的参考价值。

C - One More aab aba baa

题目链接: link.

题意:

给一个字符串,让你输出由该字符串的字母组成的所有全排列中的第k个全排列是什么?

思路:

#include <bits/stdc++.h>
using namespace std;
string s;
int k;
int a[8];
int main() {
    cin >> s >> k;
    sort(s.begin(), s.end());
    int len = s.size();
    for (int i = 0; i < len; i++) {
        a[i] = s[i] - 'a';
    }
    int cnt = 1;
    while (next_permutation(a, a + len)) {
        cnt++;
        if (cnt == k) break;
    }
    for (int i = 0; i < len; i++) {
        printf("%c", a[i] + 'a');
    }
    return 0;
}

D - Coprime 2

题目链接: link.

题意:

给你一个长度为n的数组 a 1 a_1 a1 a n a_n an,问你 1 1 1 m m m中那些数,与 a a a数组所有元素取最大公约数gcd,是1

思路:

a a a中元素质因数分解,把里面的质因子取出来,用质因子来筛 1 1 1 m m m中符合题意的数,也就是与这些质因子不是倍数关系的数。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> a[N];
int n, m;
int st[N];
int main() {
    cin >> n >> m;
    vector<int> res;
    for (int p = 0; p < n; p++) {
        int x;
        scanf("%d", &x);
        for (int i = 2; i <= x / i; i++) {
            if (x % i == 0) {
                while (x % i == 0) {
                    x /= i;
                }
                res.push_back(i);
            }
        }
        if (x > 1) res.push_back(x);
    }
    vector<int> ans;
    sort(res.begin(), res.end());
    res.erase(unique(res.begin(), res.end()), res.end());

    for (int i = 1; i <= m; i++) {
        if (st[i]) continue;
        for (int j = 0; j < res.size(); j++) {
            int x = res[j];
            int y = 1;
            while (y * x <= m) {
                st[y * x] = 1;
                y++;
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        if (!st[i]) ans.push_back(i);
    }
    cout << ans.size() << endl;
    for (int i = 0; i < ans.size(); i++) {
        cout << ans[i] << endl;
    }

    return 0;
}

E - Chain Contestant

题目链接: link.

题意:

给一个长度为 n n n的字符串,问有多少种子序列满足,在字符串中,相同字母的位置是连续的.

思路:

题目说了,最多10个字母,长度最大1000
所以可以用状压 d p dp dp来想
定义 f ( i , j , k ) f(i,j,k) f(i,j,k),到了字符串的 i i i位置, j j j字母, k k k为10个字母选与没选二进制数字。
f ( i , j , k ) = f(i,j,k)= f(i,j,k)= f ( i − 1 , j , k ) f(i-1,j,k) f(i1,j,k),这是不选 i i i号位置的字母
f ( i , c u r , 1 < < c u r ) + + f(i,cur,1 << cur) ++ f(i,cur,1<<cur)++这是第 i i i号位置,字母 c u r cur cur,选的情况
如果选了这个字母,那么这个字母之前出现过的话,必须在前一个位置,必须连续。那么就是 f ( i , c u r , j ) + = f ( i − 1 , c u r , j ) f(i,cur,j )+= f(i - 1,cur,j) f(i,cur,j)+=f(i1,cur,j)
含义就是到了 i i i号位置了,选cur这个字母,二进制下是 j j j,在 i − 1 i-1 i1决策时,选了 c u r cur cur,二进制数仍然是 j j j
如果这个字母没出现过,那么就标记这个字母出现了,利用或运算,来对二进制下的数字进行标记
f ( i , c u r , j ∣ 1 < < c u r ) + = f ( i − 1 , k , j ) f(i,cur,j | 1 << cur) += f(i - 1,k,j) f(i,cur,j1<<cur)+=f(i1,k,j)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 998244353;
ll f[1025][10][1025];
int n;
string s;

int main() {
    cin >> n >> s;
    for (int i = 1; i <= n; i++) {
        int cur = s[i - 1] - 'A';
        for (int j = 0; j < 1 << 10; j++) {
            for (int k = 0; k <= 9; k++) {
                f[i][k][j] = f[i - 1][k][j];
            }
        }
        (f[i][cur][1 << cur] += 1) %= mod;
        for (int j = 0; j < 1 << 10; j++) {
            if (j & (1 << cur)) {
                (f[i][cur][j] += f[i - 1][cur][j]) %= mod;
            } else {
                for (int k = 0; k <= 9; k++) {
                    (f[i][cur][j | 1 << cur] += f[i - 1][k][j]) %= mod;
                }
            }
        }
    }
    ll res = 0;
    for (int i = 0; i <= 9; i++) {
        for (int j = 0; j < 1 << 10; j++) {
            (res += f[n][i][j]) %= mod;
        }
    }
    cout << res % mod << endl;
    return 0;
}

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

以上是关于AtCoder Beginner Contest 215(补题)的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242