首页 > 其他分享 >Codeforces Round 862 A-E

Codeforces Round 862 A-E

时间:2023-04-04 19:02:02浏览次数:55  
标签:const int big 862 Codeforces long maxn using Round

Codeforces Round 862 (Div. 2)

先简单写一下 A-E 的题解。

A

异或的经典性质:\(x \oplus x=0\)。

B

显然要把字典序最小的那个字母放到最前面。

如果这个字母出现了很多次,那么应该选择最后一次出现的位置。这也很容易证明。

C

联立以后计算一下就行了。

比赛的时候爆了一次 int

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define pb push_back
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
const int maxn = 2e5 + 5;
const ll mod = 998244353;
const int dx[4] = { -1, 0, 1, 0 };
const int dy[4] = { 0, -1, 0, 1 };
const double eps = 1e-6;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> K(n);
    for (int i = 0; i < n; ++i) {
        cin >> K[i];
    }
    vector<tuple<ll, ll, ll>> parabolas(m);
    for (int i = 0, a, b, c; i < m; ++i) {
        cin >> a >> b >> c;
        parabolas[i] = {a, b, c};
    }
    sort(K.begin(), K.end());
    for (auto [A, B, C] : parabolas) {
        if (C <= 0) {
            cout << "NO" << endl;
        } else {
            ll sAC = sqrt(4.0 * A * C);
            if (sAC * sAC == A * C * 4) sAC--;
            auto it = lower_bound(K.begin(), K.end(), B - sAC);
            if (it == K.end()) { 
                cout << "NO" << endl;
            } else if (*it > B + sAC) {
                cout << "NO" << endl;
            } else {
                cout << "YES\n" << (*it) << endl;
            }
        }
    }
    cout << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

D

容易发现,当 \(k\) 从大到小变化时,点会一层一层的加进连通块里。

然后这个 \(k\) 的最大值是树的直径,所以点的层数应该以直径为标准进行统计。

最后模拟这个加点的过程即可。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define pb push_back
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
const int maxn = 1e5 + 5;
const ll mod = 998244353;
const int dx[4] = { -1, 0, 1, 0 };
const int dy[4] = { 0, -1, 0, 1 };

vector<int> g[maxn];
int dep[maxn], h[maxn];
int mxdep, root;
void dfs0(int u, int f) {
    dep[u] = dep[f] + 1;
    for (auto v : g[u]) {
        if (v == f) continue;
        dfs0(v, u);
    }
    if (dep[u] >= mxdep) {
        mxdep = dep[u];
        root = u;
    }
}
void dfs(int u, int f) {
    dep[u] = dep[f] + 1;
    for (auto v : g[u]) {
        if (v == f) continue;
        dfs(v, u);
    }
    h[u] = max(h[u], dep[u]);
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[u].pb(v), g[v].pb(u);
    }
    dep[0] = -1;
    mxdep = 0;
    dfs0(1, 0);
    int r = root;
    dfs0(root, 0);
    dfs(r, 0);
    dfs(root, 0);
    vector<int> cnt(n + 5, 0);
    for (int i = 1; i <= n; ++i) {
        cnt[h[i]]++;
    }
    cnt[mxdep]--;
    vector<int> ans(n + 5, n);
    for (int k = mxdep; k >= 1; --k) {
        ans[k] = ans[k + 1] - cnt[k];
    }
    for (int i = 1; i <= n; ++i) {
        cout << ans[i] << " \n"[i == n];
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

E

比赛的时候时间不够了,想写个 dsu on tree 试一下,可惜最后还是没写完。

这题的正解其实很简单,考虑整棵树的 MAD,如果这个数出现的次数不是 \(2\),那么不管断哪条边都不会改变答案。如果出现次数正好是 \(2\),那么只有这两个点之间的链被断开的时候,答案才会变化。所以先把链提取出来,然后在链上面按顺序算过去就行了。

如果没有观察到这个性质,用 dsu on tree 其实也是能做的。但是会跑的慢一些。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define pb push_back
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
const int maxn = 1e5 + 5;
const ll mod = 998244353;
const int dx[4] = { -1, 0, 1, 0 };
const int dy[4] = { 0, -1, 0, 1 };

vector<pii> g[maxn];
int w[maxn];
map<int, int> subtree, total;
set<int> smad, tmad;
int sz[maxn], big[maxn];
int L[maxn], R[maxn], dfn, node[maxn];
int ans[maxn], edge_id[maxn];
void dfs0(int u, int f) {
    L[u] = ++dfn;
    node[dfn] = u;
    sz[u] = 1;
    for (auto [v, e] : g[u]) {
        if (v == f) continue;
        edge_id[v] = e;
        dfs0(v, u);
        sz[u] += sz[v];
        if (!big[u] || sz[big[u]] < sz[v])
            big[u] = v;
    }
    R[u] = dfn;
}
void add(int x) {
    subtree[x]++;
    if (subtree[x] == 2)
        smad.insert(x);
    total[x]--;
    if (total[x] == 1)
        tmad.erase(x);
}
void del(int x) {
    total[x]++;
    if (total[x] == 2)
        tmad.insert(x);
    subtree[x]--;
    if (subtree[x] == 1)
        smad.erase(x);
}
int MAD() {
    int mx = 0;
    if (!smad.empty()) {
        mx = max(mx, *smad.rbegin());
    }
    if (!tmad.empty()) {
        mx = max(mx, *tmad.rbegin());
    }
    return mx;
}
void dfs1(int u, int f, bool keep) {
    for (auto [v, e] : g[u]) {
        if (v == f || v == big[u])
            continue;
        dfs1(v, u, false);
    }
    if (big[u]) {
        dfs1(big[u], u, true);
    }
    for (auto [v, e] : g[u]) {
        if (v == f || v == big[u])
            continue;
        for (int i = L[v]; i <= R[v]; i++) {
            add(w[node[i]]);
        }
    }
    add(w[u]);
    ans[edge_id[u]] = MAD();
    if (keep == false) {
        for (int i = L[u]; i <= R[u]; i++) {
            del(w[node[i]]);
        }
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[v].pb({ u, i });
        g[u].pb({ v, i });
    }
    for (int i = 1; i <= n; ++i) {
        cin >> w[i];
        total[w[i]]++;
        if (total[w[i]] == 2)
            tmad.insert(w[i]);
    }
    dfs0(1, 0);
    dfs1(1, 0, false);
    for (int i = 1; i < n; ++i) {
        cout << ans[i] << endl;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

不加任何优化的 dsu on tree 几乎是贴着时限过的。最好还是优化一下,比如先离散化一下,省掉两个 map,就可以跑的和正解一样快了。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define pb push_back
#define endl '\n'
using ll = long long;
using pii = pair<int, int>;
const int maxn = 1e5 + 5;
const ll mod = 998244353;
const int dx[4] = { -1, 0, 1, 0 };
const int dy[4] = { 0, -1, 0, 1 };

vector<pii> g[maxn];
int w[maxn];
int subtree[maxn], total[maxn];
set<int> smad, tmad;
int sz[maxn], big[maxn];
int L[maxn], R[maxn], dfn, node[maxn];
int ans[maxn], edge_id[maxn];
void dfs0(int u, int f) {
    L[u] = ++dfn;
    node[dfn] = u;
    sz[u] = 1;
    for (auto [v, e] : g[u]) {
        if (v == f) continue;
        edge_id[v] = e;
        dfs0(v, u);
        sz[u] += sz[v];
        if (!big[u] || sz[big[u]] < sz[v])
            big[u] = v;
    }
    R[u] = dfn;
}
void add(int x) {
    subtree[x]++;
    if (subtree[x] == 2)
        smad.insert(x);
    total[x]--;
    if (total[x] == 1)
        tmad.erase(x);
}
void del(int x) {
    total[x]++;
    if (total[x] == 2)
        tmad.insert(x);
    subtree[x]--;
    if (subtree[x] == 1)
        smad.erase(x);
}
int MAD() {
    int mx = 0;
    if (!smad.empty()) {
        mx = max(mx, *smad.rbegin());
    }
    if (!tmad.empty()) {
        mx = max(mx, *tmad.rbegin());
    }
    return mx;
}
void dfs1(int u, int f, bool keep) {
    for (auto [v, e] : g[u]) {
        if (v == f || v == big[u])
            continue;
        dfs1(v, u, false);
    }
    if (big[u]) {
        dfs1(big[u], u, true);
    }
    for (auto [v, e] : g[u]) {
        if (v == f || v == big[u])
            continue;
        for (int i = L[v]; i <= R[v]; i++) {
            add(w[node[i]]);
        }
    }
    add(w[u]);
    ans[edge_id[u]] = MAD();
    if (keep == false) {
        for (int i = L[u]; i <= R[u]; i++) {
            del(w[node[i]]);
        }
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[v].pb({ u, i });
        g[u].pb({ v, i });
    }
    vector<int> all;
    for (int i = 1; i <= n; ++i) {
        cin >> w[i];
        all.pb(w[i]);
    }
    sort(all.begin(), all.end());
    all.erase(unique(all.begin(), all.end()), all.end());
    unordered_map<int, int> wmap;
    for (int i = 0; i < all.size(); ++i)
        wmap[all[i]] = i + 1;
    for (int i = 1; i <= n; ++i) {
        w[i] = wmap[w[i]];
        total[w[i]]++;
        if (total[w[i]] == 2)
            tmad.insert(w[i]);
    }
    dfs0(1, 0);
    dfs1(1, 0, false);
    for (int i = 1; i < n; ++i) {
        if (ans[i]) ans[i] = all[ans[i] - 1];
        cout << ans[i] << endl;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

标签:const,int,big,862,Codeforces,long,maxn,using,Round
From: https://www.cnblogs.com/theophania/p/cf862.html

相关文章

  • Codeforces Round 717 (Div. 2) B. AGAGA XOOORRR(位运算)
    https://codeforces.com/contest/1516/problem/B题目大意:给定长度为n的数组a,问我们能不能一直选择两个相邻的元素进行异或后,删除这两个值,把异或值留下来,最后剩下>=2个数字,它们都是相同的?可以做到输出YES,不能的话输出NO。input23022423110outputYESNO题......
  • CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)-C
    参考了佬的c题题解思路,感觉很巧妙,记录一下https://zhuanlan.zhihu.com/p/618685370#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=2*100010;inta[N];voidsolve(){ intn,c,d; cin>>n>>c>>d; set<int>se......
  • cf-div.2-862d
    题目链接:https://codeforces.com/contest/1805/problem/D赛时没过的题。思路:首先发现一个性质:对于k来说,如果树上的一个点到树的直径的两个端点的距离都小于k的话,那么这个点一定是一个孤立点。证明:采用反证法:假设\(x,y\)为树的直径的两个端点,\(a,b\)为另外两个点,且有\(d[a][x]<k......
  • Codeforces Round 862 (Div. 2) A-D题解
    比赛地址A.WeNeedtheZero题意:给出一个数组,对任意1<=i<=n,令bi=aix,问是否存在x,使得b<sub>1</sub>b2...bn=0Solution如果n为奇数,那么x一定存在,因为偶数个x异或得到的是0,直接令x=0(a<sub>1</sub>a2...an)即可如果n为偶数,那么x取任何值都不会影响结果,所以只用看a1a<sub>2</sub......
  • Codeforces Round 862 (Div. 2) (4.2)
    CodeforcesRound862(Div.2)A-WeNeedtheZero思路:某个数被异或两次相当于没变,即判断n的奇偶性;n为偶数时判断所有数异或后的数是否为0,若为0,输出任意数;n为奇数时答案为所有数异或后的值#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>PII;consti......
  • Codeforces Round 862 (Div. 2)A-C思路复盘
    感觉这场前三题都简单,复盘一下赛时的脑回路QAQ,c二分wa了四发赛后才过的血亏A题意:问是否能找到一个数x,有\(b_i=a_i⊕x\),使得\(b\)数组的总异或和为0。思路:赛时模拟样例可以发现先把a数组的总异或和求出来假设为x,然后由异或性质可知相同为0,不同为1,可知这个x可能就是答案。然......
  • background-color 只填充容器的一半
     关键字的取值:toright  (表示从左往右渐变)toleft    (表示从右往左渐变)totop    (表示从下往上渐变)tobottom (表示从上往下渐变)角度的取值: 0deg  (从下到上totop)  180deg(从上到下tobottom)90deg  (从左到右toright)-90deg......
  • CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)- Make It Permutation
    题目链接:Problem-C-Codeforces  #include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;#defineendl"\n"intmain(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);intT=1;cin>>T;while(......
  • CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)
    题目链接C核心思路其实这个操作无非就两种:插入和删除。我们可以把重复的元素都先删除,因为这肯定是每个操作必须要做的。我们可以从最基础的情况出发也就是怎么构造出来\(1\sima[i]\)的序列呢。肯定是吧\(i\simn\)之后的序列都删除吧,然后把前面缺少的再补上去吧。所以我们......
  • CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!) A-E
    从C题开始写好了MakeItPermutation首先我们分析假如我们确定了要选择一个长度为n的序列,该怎么计算代价很明显一个是算保留多少个一个是算要加多少个,然后如果我们算完了选择长度n-1的序列那么更新答案的时候只需要看n这个数字是否存在就可以了,然后更新一下删掉多少个数字......