AtCoder Beginner Contest 133 解题报告 (A ~ E)

比赛地址:AtCoder Beginner Contest 133

A - T or T

题目大意:\(n\) 个同学一起去旅行,坐火车的话每人要 \(a\) 元,做出租车的话总共要 \(b\) 元,问最少花费多少元?

解题思路:直接计算取最小值即可

#include <cstdio>
#include <algorithm>

int main() {
    int n, a, b;
    scanf("%d%d%d", &n, &a, &b);
    printf("%d", std::min(a * n, b));
    return 0;
}

B - Good Distance

题目大意:\(D\) 维空间内有 \(n\) 个点,问有多少点对,两个点之间的距离为整数, \(D,n\le 10\)

解题思路:由于数据范围很小,暴力计算判断即可

#include <cstdio>
#include <cmath>

int n, d, ans;
int point[11][11];

bool get_dist(int x, int y) {
    int tmp = 0;
    for (int i = 1; i <= d; ++i) {
        tmp += pow(point[x][i] - point[y][i], 2);
    }
    if (int(sqrt(tmp)) == sqrt(tmp)) 
        return true;
    else 
        return false;
}

int main() {
    scanf("%d%d", &n, &d);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= d; ++j) {
            scanf("%d", &point[i][j]);
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            ans += get_dist(i, j);
        }
    }
    printf("%d", ans);
    return 0;
}

C - Remainder Minimization 2019

题目大意:在区间 \([L,R]\) 内寻找两个不同的整数 \(i\)\(j\) ,使得 \(j \times j\ Mod\ 2019\) 最小,输出这个最小值。

解题思路:如果 \(R - L \ge 2019\) ,那么在区间 \([L,R]\) 内一定存在一个数 \(n\) 使得 \(n\ Mod\ 2019 = 0\) ,此时答案一定为 \(0\) ,所以当 \(R - L\ge 2019\) 时,我们直接让 \(R = L + 2019\) 即可,此操作过后,数据范围大大减小,就可以在区间 \([L,R]\) 内暴力枚举了。

值得注意的是:不能想当然地认为找到模 \(2019\) 最小的两个数相乘就可以得到答案了,因为这两个数相乘得到的模数可能是 \(2018\) ,而且存在另外两个数相乘模 \(2019\) 的值更小。

#include <cstdio>
#include <algorithm>

int left, right, ans;
int cnt[2019], min[2];

int main() {
    scanf("%d%d", &left, &right);
    right = std::min(right, left + 2019);
    ans = 2019;
    for (int i = left; i <= right ; ++i) {
        for (int j = i + 1; j <= right; ++j) {
            ans = std::min(ans, (i % 2019) * (j % 2019) % 2019);
        }
    }
    printf("%d", ans);
    return 0;
}

D - Rain Flows into Dams

题目大意:有 \(n\)\(n\) 为奇数)座山围成一圈,相邻两座山之间有水坝,如果山上下了 \(2x\) 的雨,那么与这座山相邻的两座水坝各会积累 \(x\) 的水量,现在给出每个水坝的最终积水量,求每座山上下了多少的雨。

解题思路:我们不妨设编号为 \(i\) 的山上下了 \(x_i\) 的雨,编号为 \(i\) 的大坝积水量为 \(A_i\) ,那么根据题意我们可以得到如下的方程组:

\[ \left\{ \begin{array}{c} x_1 + x_2 = 2A_1\\ x_2 + x_3 = 2A_2\\ x_3 + x_4 = 2A_3\\ ...\\ x_n + x_1 = 2A_n \end{array} \right. \]

由于 \(n\) 为奇数,我们将所有奇数行的方程相加就可以得到 \(\sum\limits_{i = 1}^{n}x_i + x_1\) 的结果,而 \(\sum\limits_{i = 1}^{n}x_i = \sum\limits_{i = 1}^nA_i\) ,由此我们就可以算出 \(x_1\) ,由此代入方程组,就可以解出所有的 \(x\) 了。

#include <cstdio>

const int MAXN = 1e5 + 5;

int n, cnt, sum;
int arr[MAXN], ans[MAXN];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &arr[i]);
        sum += arr[i];
        if (i & 1) 
            cnt += (arr[i] << 1);
    }
    ans[1] = cnt - sum;
    for (int i = 1; i < n; ++i) {
        ans[i + 1] = (arr[i] << 1) - ans[i];
    }
    for (int i = 1; i <= n; ++i) {
        printf("%d ", ans[i]);
    }
    return 0;
}

E - Virus Tree 2

题目大意:给你有一棵有 \(n\) 个节点的树和 \(k\) 种颜色,现在要将这棵树的每一个节点都染上色,要求距离小于等于 \(2\) 的点不能染上相同的颜色吗,求染色方案数对 \(1000000007\) 取模。

解题思路:我们考虑解出每一个节点有多少种染色方案,我们令 \(dp[i]\) 表示第 \(i\) 个节点有多少个染色的方案,那么我们如果从根节点开始 DP ,先考虑每一条链的情况,记当前节点为 \(nv\) ,如果是根节点,那么 \(dp[nv] = k\) ,如果是根节点的儿子节点,那么 \(dp[nv] = k - 1\) ,如果是根节点的孙子节点或者更深的节点,那么他不仅会受到父节点的影响,也会受到祖父节点的影响,所以 \(dp[nv] = k - 2\) ,这样我们就可以处理出一条链上所有的节点的染色方案数。现在考虑一般情况,我们发现一个节点的兄弟也会对他产生影响,因此在处理一个节点的儿子时,它的儿子的 \(dp\) 值是不断递减的,但是这并不会影响它的某一个孙子的答案,因为它的孙子不会受到儿子的其他兄弟的影响(树上距离大于 \(2\) ),这样子我们就处理出了一般情况下所有节点的染色方案数,将他们相乘就可以得到答案了。

#include <cstdio>
#include <vector>

typedef long long int ll;

const int MAXN = 1e5 + 5;
const int mod = 1e9 + 7;

int n, k, u, v;
ll ans;
ll dp[MAXN];

std::vector<int> con[MAXN];

void ins(int start, int end) {
    con[start].push_back(end);
}

void get_dp(int nv, int fa) {
    int tmp = (nv == 1) ? (k - 1) : (k - 2);
    for (int i = 0; i < con[nv].size(); ++i) {
        if (con[nv][i] == fa)
            continue;
        else {
            dp[con[nv][i]] = tmp;
            get_dp(con[nv][i], nv);
            --tmp;
        }
    }
}

int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i < n; ++i) {
        scanf("%d%d", &u, &v);
        ins(u, v);
        ins(v, u);
    }
    dp[1] = k;
    get_dp(1, 0);
    ans = 1;
    for (int i = 1; i <= n; ++i) {
        ans = ans * dp[i] % mod;
    }
    printf("%lld", ans);
    return 0;
}

转载于:https://www.cnblogs.com/lornd/p/11162677.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值