2020牛客寒假算法基础集训营3

题目链接:https://ac.nowcoder.com/acm/contest/3004

假算法集训营第3期,快来看看你有哪些基础知识还不会吧!~

这几天有时间先补图论的坑,再补LCT吧,字符串和几何目前只能选择相信队友。

A - 牛牛的DRB迷宫I

水题

G题的不带修形式。甚至从这道题已经可以知道下一道题的线段树要怎么维护了。

题意:有一个01串,求每对1之间的距离和。

题解:每右移一位,总的距离就增加左侧的1的数量。在遇到1的时候统计“它作为右边的1时”的贡献。

char g[100005];
void test_case() {
    int n;
    scanf("%d%s", &n, g + 1);
    ll ans = 0, sum = 0;
    int cnt = 0;
    for(int i = 1; i <= n; ++i) {
        if(g[i] == '1') {
            ans += sum;
            ++cnt;
        }
        sum += cnt;
        if(sum >= MOD)
            sum -= MOD;
    }
    ans %= MOD;
    printf("%lld
", ans);
}

H - 牛牛的k合因子数

题意:给一个n<=1e5,求范围中有多少个数恰好有k个合数因子。

题解:由于 (sumlimits_{i=1}^{n}lfloorfrac{n}{i} floor ~ O(nlogn)) ,直接暴力求。

const int MAXN = 1e5;
int p[MAXN + 5], ptop;
bool pn[MAXN + 5];

void sieve() {
    int n = MAXN;
    pn[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!pn[i])
            p[++ptop] = i;
        for(int j = 1; j <= ptop; j++) {
            int t = i * p[j];
            if(t > n)
                break;
            pn[t] = 1;
            if(i % p[j] == 0)
                break;
        }
    }
}

int cnt[MAXN + 5];
int ans[MAXN + 5];

void test_case() {
    sieve();
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 2; i <= n; ++i) {
        if(pn[i]) {
            for(int j = i; j <= n; j += i)
                ++cnt[j];
        }
    }
    for(int i = 1; i <= n; ++i)
        ++ans[cnt[i]];
    while(m--) {
        int k;
        scanf("%d", &k);
        printf("%d
", ans[k]);
    }
}

*D - 牛牛与二叉树的数组存储

一开始觉得:“什么垃圾题,怎么花钱买了这种题。”

然后就段错误了。事实证明不能够小看和轻视。

题意:给一棵满二叉树,上面恰好有[1,m]号节点,按顺序输出他们的父亲和孩子们。

题解:模拟,然后小心越界。

int data[200005], pos[200005];

void test_case() {
    int n, m = 0;
    scanf("%d", &n);
    memset(data, -1, sizeof(data));
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &data[i]);
        if(data[i] != -1) {
            pos[data[i]] = i;
            m = max(m, data[i]);
        }
    }
    printf("The size of the tree is %d
", m);
    printf("Node %d is the root node of the tree
", data[1]);
    for(int i = 1; i <= m; ++i)
        printf("The father of node %d is %d, the left child is %d, and the right child is %d
", i, data[pos[i] / 2], data[pos[i] * 2], data[pos[i] * 2 + 1]);
}

*C - 牛的数组越位

题意:告诉你C++中二维数组中中括号的运算规则,以及某编译器对此ub的处理。要求模拟给数组赋值,检测是否有ub甚至真正的re。

题解:按题意模拟。

总结:没写过这种**bug就不知道自己这么**,居然连

    if(0 <= x < n)
        statement;

这种表达都出来了。其实编译器已经给出了警告,记得在新电脑上调好编译器并打开 -Wall 开关。

KisekiPurin.cpp|69|warning: comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]|
int a[1000005];
void test_case() {
    int n, m, p;
    scanf("%d%d%d", &n, &m, &p);
    memset(a, 0, sizeof(a[0]) * (n * m));
    bool ub = 0, re = 0;
    while(p--) {
        int x, y, v;
        scanf("%d%d%d", &x, &y, &v);
        if(re)
            continue;
        ll t = 1ll * x * m + y;
        if(0 <= x && x < n) {
            if(0 <= y && y < m)
                a[t] = v;
            else {
                ub = 1;
                if(0 <= t && t < n * m)
                    a[t] = v;
                else
                    re = 1;
            }
        } else {
            ub = 1;
            if(0 <= t && t < n * m)
                a[t] = v;
            else
                re = 1;
        }
    }
    if(re) {
        puts("Runtime error");
        return;
    }
    int top = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j)
            printf("%d%c", a[top++], " 
"[j == m - 1]);
    }
    if(ub)
        puts("Undefined Behaviour");
    else
        puts("Accepted");
}
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12286122.html