Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

A - Happy Birthday, Polycarp!

题意:给一个n<=1e9,求[1,n]里面有多少个数字是有单个数字重复多次构成的。

题解:这种数字本身不对,一个一个暴力验证就可以。假如数据量继续扩大,那么把所有的数字生成出来(至多200个,当1e18时),排个序,然后把n在里面二分,应该速度会大概提升10倍。

void test_case() {
    int n, ans = 0;
    scanf("%d", &n);
    for(int x = 1; x <= 9; ++x) {
        ll tmp = x;
        while(tmp <= n) {
            ++ans;
            tmp = 10 * tmp + x;
        }
    }
    printf("%d\n", ans);
}

B - Make Them Odd

题意:给一个序列,你每次可以选一个偶数,然后把所有等于这个偶数的数变成原来的一半,求最小的操作步数。

题解:每次取最大的出来贪心,每个数最多被贪30次,再加上优先队列的log就不太美妙了,但是总的复杂度依然是nlogn+nlogai。经过观察发现能够连在一起的都是非2的部分一样的数,也就是每种除去2的幂之后一样的数贡献这一种的最高2的幂,还是要用map去统计,复杂度没变。

附带一个更快的分解2的幂次的办法:__builtin_ctz(x),返回后跟0的数量。来源:https://www.cnblogs.com/liuzhanshan/p/6861596.html

int a[200005];
map<int, int> m;
void test_case() {
    int n, ans = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        int tmp = __builtin_ctz(a[i]);
        m[a[i] >> tmp] = max(m[a[i] >> tmp], tmp);
    }
    for(auto &i : m)
        ans += i.second;
    m.clear();
    printf("%d\n", ans);
}
上一篇:606页Android最新面试题含答案,助力成为offer收割机


下一篇:链式栈的实现(头文件及源程序)