Problem A kotori和糖果

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

题意:合并,求最小代价值。
思路:将一个堆二分,递归求该堆合并的最小代价值。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll cnt[100005], n;
ll slove(ll x) {
    if (x <= 100000) {
        if (cnt[x])
            return cnt[x];
        if (x < 2 || !(x & (x - 1)))
            return cnt[x] = 0;
        if (x & 1)
            return cnt[x] = slove(x >> 1) + slove((x >> 1) + 1) + 1;
        return cnt[x] = slove(x >> 1) << 1;
    }
    if (x < 2 || !(x & (x - 1)))
        return 0;
    if (x & 1)
        return slove(x >> 1) + slove(x >> 1 + 1) + 1;
    return slove(x >> 1) << 1;
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld", &n);
        printf("%lld\n", slove(n));
    }
    return 0;
}

Problem B kotori和气球

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

题意:求满足要求的m个气球的排列数。
思路:组合数学,第1个有n种选择,则剩余的m-1个都只有n-1种选择,故总的排列数为

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int MOD = 109;
int pow_(int a, int b) {
    int cnt = 1;
    while (b) {
        if (b & 1)
            cnt = cnt * a % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return cnt;
}
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    printf("%d\n", pow_(n - 1, m - 1) * n % MOD);
    return 0;
}

Problem C kotori和出道

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

题意:约瑟夫环问题。
思路:数据过大不能用递归解决,打表找规律得2*(n-cnt)+1, 其中cnt为不大于n的最大2的整数幂。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int t;
    ll n;
    scanf("%d", &t);
    while (t--) {
        ll cnt = 1;
        scanf("%lld", &n);
        while (cnt << 1 <= n)
            cnt <<= 1;
        printf("%lld\n", ((n - cnt) << 1) + 1);
    }
    return 0;
}

Problem D kotori和迷宫

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

题意:问能到达的出口数量和最近的出口距离。
思路:BFS。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
struct edge {
    int x, y, t;
}p;
char mp[35][35];
int n, m, cnt = 0, min_ = inf, vis[35][35];
int arr[4][2] = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}}; 
void BFS(int x, int y) {
    int tx, ty;
    queue <edge> Q;
    Q.push((edge){x, y});
    while (!Q.empty()) {
        p = Q.front();
        Q.pop();
        if (mp[p.x][p.y] == 'e') {
            cnt++;
            min_ = min(min_, p.t);
            continue;
        }
        for (int i = 0; i < 4; i++) {
            tx = p.x + arr[i][0];
            ty = p.y + arr[i][1];
            if (tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && mp[tx][ty] != '*'){
                vis[tx][ty] = true;
                Q.push((edge){tx, ty, p.t + 1});
            }
        }
    }
}
int main() {
    int ex, ey;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf(" %c", &mp[i][j]);
            if (mp[i][j] == 'k')
                ex = i, ey = j;
        }
    }
    BFS(ex, ey);
    if (min_ < inf)
        printf("%d %d\n", cnt, min_);
    else printf("-1\n");
    return 0;
}

Problem E kotori和素因子

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

题意:每个都贡献一个素因子,保证所有的素因子互不相同,求素因子和的最小值。
思路:线性筛出1~1000之内的所有素数,然后DFS求解最小值。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int MAXM = 1005;
const int inf = 0x3f3f3f3f;
bool isprime[MAXM];
int n, cnt = 0, min_ = inf, s[15], pre[MAXM], vis[MAXM];
void prime() {
    isprime[0] = isprime[1] = true;
    for (int i = 2; i < MAXM; i++) {
        if (!isprime[i])
            pre[cnt++] = i;
        for (int j = 0; j < cnt && i * pre[j] < MAXM; j++) {
            isprime[i *pre[j]] = true;
            if (!(i % pre[j]))
                break;
        }
    }
}
void DFS(int x, int ans) {
    if (x >= n) {
        if (min_ > ans)
            min_ = ans;
        return ;    
    }
    for (int i = 0; i < cnt; i++) {
        if (!(s[x] % pre[i]) && !vis[pre[i]]) {
            vis[pre[i]] = true;
            DFS(x + 1, ans + pre[i]);
            vis[pre[i]] = false;
        }
    }
}
int main() {
    prime();
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &s[i]);
    DFS(0, 0);
    if (min_ < inf)
        printf("%d\n", min_);
    else printf("-1\n");
    return 0;
}

Problem F kotori和n皇后

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

题意:判断是否存在两个皇后可以互相攻击。
思路:利用n皇后相互攻击的规律,利用set求解。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
set <int> setr, setc, set45, set135;
bool Judge(int x, int y) {
    if (setr.count(x) || setc.count(y) || set45.count(x - y) || set135.count(x + y))
        return true;
    return false;
}
int main() {
    int n, m, t, x, y, min_ = inf;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &x, &y);
        if (min_ >= inf) {
            if (Judge(x, y))
                min_ = i;
            setr.insert(x);
            setc.insert(y);
            set45.insert(x - y);
            set135.insert(x + y);
        }
    }
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &m);
        if (m >= min_)
            printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

Problem G kotori和抽卡(二)

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

题意:抽n次恰好m张R卡。
思路:二项分布,

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m;
    double ans = 1.0;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n - m; i++)
        ans *= 0.2 * (n - i + 1) / i;
    for (int i = 0; i < m; i++)
        ans *= 0.8;
    printf("%.4lf\n", ans);
    return 0;
}

Problem H andy和购物

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

题意:n个价格有n个折扣,求打折后的最小花费。
思路:贪心,用小的价钱打大的折。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
int prc[1010];
double dsc[1010];
int main() {
    int t, n;
    scanf("%d", &t);
    while(t--) {
        double res = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d", &prc[i]);
        for (int i = 0; i < n; i++)
            scanf("%lf", &dsc[i]);
        sort(prc, prc + n);
        sort(dsc, dsc + n);
        for (int i = 0; i < n; i++)
            res += prc[i] * dsc[n - i - 1];
        printf("%.3lf\n", res);
    }
   return 0;
}

Problem I andy种树

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

题意:求q次浇水后,n棵树的最终高度。
思路:差分。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
int pre[100005];
int main() {
    int t, n, l, r;
    scanf("%d%d", &n, &t);
    while(t--) {
        scanf("%d%d", &l, &r);
        pre[l]++;
        pre[r + 1]--;
    }
    for (int i = 1; i <= n; i++) {
        pre[i] += pre[i - 1];
        printf("%d%c", pre[i], "\n "[i != n]);
    }
    return 0;
}

Problem J andy的树被砍了

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

题意:每天都要种树,每天也要砍树,求n棵树将在哪天被砍死。
思路:对位置i,应该找i~n+1中c[i]前缀和超过h[j]的最小位置。因此要求出c的前缀和c,二分查找c[j-1]=h[j]的最小位置。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
long long c[N], h[N];
int slove(int l, int r, long long k) {
    int mid;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (c[mid] >= k)
            r = mid - 1;
        else l = mid + 1;
    }
    return l;
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &h[i]);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &c[i]);
        c[i] += c[i - 1];
    }
    c[n + 1] = c[n] + N;
    for (int i = 1; i <= n; i++)
        printf("%d%c", slove(i, n + 1, c[i - 1] + h[i]), "\n "[i != n]);
    return 0;
}