Codeforces Round #705 (Div. 2)

Contest Info


Practice Link

Solved A B C D E F
4 / 6 O O O Ø - -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Anti-knapsack

题意:
给你两个正整数\(n\)\(k\),在\(1\)~\(n\)中求一个最大的集合,使得这个集合的任意子集内所有元素的和都不等于\(k\)

思路:
大于\(k\)的数可以直接取。然后我们考虑\(1\)~\(k - 1\),发现两端对应的数加起来等于\(k\),所以只取一端的数就可以了。

#include <bits/stdc++.h>

using namespace std;

#define endl "\n"

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int n, k;

void solve() {
    cin >> n >> k;
    cout << n - k + k / 2 << endl;
    for (int i = k + 1; i <= n; ++i) {
        cout << i << " ";
    }
    for (int i = k - 1; i >= (k + 1) / 2; --i) {
        cout << i << " ";
    }
    cout << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(20);
    int _T = 1;
    cin >> _T;
    while (_T--) solve();
    return 0;
}

B. Planet Lapituletti

题意:
我们定义一天有\(h\)个小时,每小时\(m\)分钟。现在给你一个时间,求在未来最接近它的一个时间,使得我们从镜子中读到的时间也是合法的。

思路:
从镜子中读取的时间和数字都刚好是相反的,所以我们搞个数组,先判断下从镜子中能读到的数字是否合法,然后在把读到的时间算出来,和\(h\)还有\(m\)进行比较,判断是否合法。一直往后取直到合法为止。

#include <bits/stdc++.h>

using namespace std;

template <class T> inline void read(T &x) {
    int f = 0; x = 0; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    if (f) x = -x;
}

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int a[] = {0, 1, 5, -1, -1, 2, -1, -1, 8, -1};
int hh, mm, h, m;
int H[3], M[3];

bool check() {
    H[1] = a[mm % 10];
    H[2] = a[mm / 10 % 10];
    M[1] = a[hh % 10];
    M[2] = a[hh / 10 % 10];
    for (int i = 1; i <= 2; ++i) {
        if (H[i] == -1 || M[i] == -1) return false;
    }
    int fh = H[1] * 10 + H[2];
    int fm = M[1] * 10 + M[2];
    return fh < h && fm < m;
}

void solve() {
    scanf("%d %d", &h, &m);
    scanf("%d:%d", &hh, &mm);
    while (!check()) {
        mm += 1;
        if (mm >= m) mm = 0, hh++;
        if (hh >= h) hh = 0;
    }
    printf("%02d:%02d\n", hh, mm);
}

int main() {
    int _T = 1;
    read(_T);
    while (_T--) solve();
    return 0;
}

C. K-beautiful Strings

题意:
给你一个长为\(n\),仅由小写字母构成的字符串,求一个字典序大于等于原字符串且字典序最小的字符串,使得其中所有元素的数量都是\(k\)的倍数。

思路:
\(n\)\(k\)的倍数时,就一定有解,否则一定无解。

当我们将第i位的字符变大的时候,第\(i + 1\)到第\(n\)位的字符就可以任意改变了。要让字符串的字典序最小,我们应该贪心地让后面的字符变大。所以我们从后往前枚举字符,进行变大处理,同时检查在拥有\(n - i\)个任意字符时,能否让所有字符的数量都变成\(k\)的倍数。如果检查完任意字符仍有剩余,那么由于第一步的特判,剩下来的数量一定也是\(k\)的倍数。我们将剩下来的字符全部处理成'\(a\)'​,然后先输出前面不是任意字符的字符,然后优先输出剩余的'\(a\)',接下来从'\(a\)'到'\(z\)'输出需要额外添加的字符,即可得到字典序最小的满足要求的字符串。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;

char s[N];
int n, k;
int num[207], to[207];

bool check(int go) {
    for (int i = 'a'; i <= 'z'; ++i) {
        go -= num[i] % k? k - (num[i] % k) : 0;
    }
    return go >= 0;
}

void solve() {
    scanf("%d %d", &n, &k);
    scanf("%s", s);
    if (n % k) {
        puts("-1");
        return;
    }
    for (int i = 'a'; i <= 'z'; ++i) {
        num[i] = 0;
    }
    for (int i = 0; i < n; ++i) {
        num[ s[i] ]++;
    }
    if (check(0)) {
        printf("%s\n", s);
        return;
    }
    int len = 0;
    for (int i = n - 1; i >= 0; --i) {
        int f = 0;
        for (int j = s[i] + 1; j <= 'z'; ++j) {
            num[j - 1]--;
            num[j]++;
            if (check(len)) {
                f = 1;
                s[i] = j;
                break;
            }
            if (j == 'z') {
                num[j]--;
                num[ s[i] ]++;
            }
        }
        if (f) break;
        num[ s[i] ]--; // 注意消除这个字符的数量
        len++;
    }
    for (int i = 0; i < n - len; ++i) {
        printf("%c", s[i]);
    }
    for (int i = 'a'; i <= 'z'; ++i) {
        to[i] = 0;
        if (num[i] % k) {
            to[i] = k - (num[i] % k);
            len -= to[i];
        }
    }
    for (int i = 1; i <= len; ++i) printf("a");
    for (int i = 'a'; i <= 'z'; ++i) {
        while (to[i]) {
            printf("%c", i);
            to[i]--;
        }
    }
    printf("\n");
}

int main() {
    int _T = 1;
    scanf("%d", &_T);
    while (_T--) solve();
    return 0;
}
/*
1
9 3
aabzzzzzz
*/

D. GCD of an Array

题意:
给你一个序列\(a_1\) ~ \(a_n\),每次操作将\(a_i\)元素增大\(x\)倍,输出每次操作后整个序列的\(gcd\)\(mod\) \(10^9 + 7\)

思路:
我们考虑整个序列的\(gcd\)值,可以把它看成\({p_1}^{k_1} * {p_2}^{k_2} * ... * {p_m}^{k_m}\),其中\(p_i\)为所有元素都拥有的质因数,\(k_i\)\(p_i\)这个质因数在所有值中拥有数量的最小值。由此也可以推出序列的\(gcd\)值是只增不减的。我们将初始答案置为\(1\)\(a_i\)也都置为\(1\),每次给\(a_i\)增加\(x\)倍时,对\(x\)进行质因数分解。假设我们当前分解出来的质因数为\(p\),如果\(a_i\)先前没有\(p\)这个质因数,那么对\(p\)的总体数量有一个贡献。当\(p\)的数量达到\(n\)时,说明每个\(a_i\)都拥有了\(p\)这个质因数,会对答案产生贡献。我们找出上一次\(p\)对答案的贡献\(k\)以及当前序列所有元素中\(p\)的最小数量,产生贡献的数量即为\(p\)的最小数量减去上一次\(p\)的贡献,将答案乘上这么多个\(p\)就行了。我们可以用\(map\)来记录\(a_i\)中每个质因数的数量,然后用\(multiset\)来维护序列所有元素中\(p\)的最小数量。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 7;
const ll mod = 1e9 + 7;

map<int, int> cntDiv[N];
multiset<int> cntTot[N];
int pre[N], tot[N], nxt[N], n, q, v, id;
ll ans = 1;

ll powmod(ll a, ll b) {
    ll res = 1;
    a %= mod;
    for (; b; b >>= 1) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
    }
    return res;
}

void add(int k, int x) {
    while (x != 1) {
        int div = nxt[x], add = 0;
        while (nxt[x] == div) add++, x /= nxt[x];

        if (!cntDiv[k].count(div)) {
            tot[div]++;
        }
        if (cntDiv[k][div]) {
            cntTot[div].erase(cntTot[div].find(cntDiv[k][div]));
        }
        cntDiv[k][div] += add;
        cntTot[div].insert(cntDiv[k][div]);
        if (tot[div] == n) {
            int num = *cntTot[div].begin() - pre[div];
            ans = ans * powmod(div, num) % mod;
            pre[div] = *cntTot[div].begin();
        }
    }
}

void solve() {
    scanf("%d %d", &n, &q);

    for (int i = 2; i < N; ++i) {
        if (nxt[i] == 0) {
            nxt[i] = i;
            if (i > 10000) continue;
            for (int j = i * i; j < N; j += i) {
                if (nxt[j] == 0) nxt[j] = i;
            }
        }
    }
    
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &v);
        add(i, v);
    }

    for (int i = 1; i <= q; ++i) {
        scanf("%d %d", &id, &v);
        add(id, v);
        printf("%lld\n", ans);
    }
}

int main() {
    int _T = 1;
    while (_T--) solve();
    return 0;
}
posted @ 2021-03-07 11:49  stff577  阅读(147)  评论(0)    收藏  举报