CodeTON Round 1 个人题解 A-E

​​​A

题意:

在序列a_1a_n上定义“好对”(i, j)为对于任意a_k(1 \leq k\leq n)都有|a_i - a_k| - |a_k - a_j| = |a_i - a_j

思路:

易知取最大最小值下标即可,min/max_element方便好用

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
int n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;
int num[100005];
void solve() {
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> num[i];
    }
    cout << min_element(num, num+n) - num+1 << ' ' << max_element(num, num+n) - num+1 << '\n';

}

int main () {
    //	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    oT_To = 1;
    cin >> oT_To;
    while (oT_To--) {
        solve();
    }
}


B

题意:

给出n个数,每次删除其中的任意一个数,然后将剩下的每个数减去这个数,重复操作至只剩下一个数为止,问剩下的数是否可能等于k

思路:

减去a_i_0后剩下的数为a_1 - a_i_0a_2 - a_i_0 ... a_n - a_i_0

再减去第i1项,则数列为a_1 - a_i_1,   a_2 - a_i_1 ... a_n - a_i_1

以此类推,最后剩下的数即为某两项之差

所以该题就转化为了求是否有 a_i - a_j  = k,即 a_i = k + a_j

升序排序后依次将a_i+k插入set并查询a_i是否存在于set中即可

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
int n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;
int num[200005];
ll sum;
void solve() {
    sum = 0;
    cin >> n >> k;
    set<int> st;
    mark = 0;
    for (int i = 0; i < n; ++i) {
        cin >> num[i];
    }
    sort(num, num+n);
    for (int i = 0; i < n; ++i) {
        if (st.count(num[i])) {
            mark = 1;
            break;
        }
        st.insert(num[i]+k);
    }
    if (mark) {
        cout << "YES\n";
    } else cout << "NO\n";

}

int main () {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    oT_To = 1;
    cin >> oT_To;
    while (oT_To--) {
        solve();
    }
}


C

 题意:

给出n个数,每次操作都可以使所有数都等于mod x(x \geq 2), 问任意次操作后是否能使所有数相等

 思路:

首先易知每次mod最大值即可让所有大于等于2的数变为0,

或每次mod最大值-1即可让所有大于等于3的数变为1,

但后者若有两个数相邻(a+1=b)则无法这样操作,

会使两数中较小的数变为0,较大的数变为1,从而不可能符合题意。

故如果给出的n个数中有1并且有相邻的数时无解,

否则若不含1则重复mod最大

值,反之mod最大值-1即可

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
int n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;

void solve() {
    cin >> n;
    mark = 0;

    set<int>st;
    for (int i = 0; i < n; ++i) {
        cin >> a;
        st.insert(a);
    }
    for (int i : st) {
        if (st.count(i+1)) {
            mark = 1;
            break;
        }
    }
    if (mark && st.count(1)) cout << "NO\n";
    else cout << "YES\n";

}

int main () {
    //	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    oT_To = 1;
    cin >> oT_To;
    while (oT_To--) {
        solve();
    }
}


D

题意:

对于一个数n,如果它能被表示成k个mod k不同的数之和,那么它就是一个“k好”数,给出一个数,问它是否是k好数,如果是则输出任意一个k

思路:

首先分析k好数定义可知,k好数可以表示为1+2+...+k + k*a (a\geq 0) , 即 \frac{k*(k+1)}{2} + k*a 

 当k为偶数时,该式为\frac{k}{2} (k+1+2a);当k为奇数时,该式为k*\frac{k+1+2a}{2}

观察以上两个式子可知,k好数总能化为一个形如\frac{(2x) * (2y+1)}{2}(x, y \epsilon Z^{+})的式子

所以我们只需要将n转换为一个奇数和偶数的积即可

具体做法连续除2即可,我们经过这个操作就可以得到一对b, c满足b*c=n且bc一为奇数一为偶数

(注意2的若干次方必定不是k好数,因为k > 1)

将偶数*2后的较小数作为k带入方程则可解出答案,k即为min(奇数,偶数*2)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
ll n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;

void solve() {
    cin >> n;
    a = 2;
    while ((n & 1) == 0) {
        n >>= 1, a <<= 1;
    }
    if (n == 1) {
        cout << "-1\n";
        return;
    }
    cout << min(a, n) << '\n';
}

int main () {
    oT_To = 1;
    cin >> oT_To;
    while (oT_To--) {
        solve();
    }
}


E

题意:

给出一颗树,要求给每个点赋权值使得删除树上任意一个点后剩下的每个连通块上的点权之和都相同

思路:

考虑使整颗数的点权之和为0,任意确定一个根节点(高度为0)后,

以高度为奇数的节点作为根节点的子树的点权和为1,

以高度为偶数的节点作为根节点的子树的点权和为-1,

将每个点的权值设为1或-1(根节点为0)然后减去子节点个数*-1或1即可实现。

这样构造出来的树任意删去一个节点后剩下的每个连通块都是1(-1,由删去节点的高度决定)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
int n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;
vector <vector <int> > ve;
vector <int> val;

void dfs(int now, int fa, int d) {
    val[now] = d;
    val[fa] -= d;
    for (int i : ve[now]) {
        if (i != fa) {
            dfs(i, now, d == 0 ? 1 : -d);
        }
    }
}

void solve() {
    cin >> n;
    ve = vector <vector <int>> (n+1);
    val = vector <int> (n+1);
    for (int i = 1; i < n; ++i) {
        cin >> a >> b;
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    dfs(1, 0, 0);
    for (int i = 1; i <= n; i++) {
        cout << val[i] << (i == n ? '\n' : ' ');
    }
}

int main () {
    //	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    oT_To = 1;
    cin >> oT_To;
    while (oT_To--) {
        solve();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值