Codeforces Round #628 (Div. 2)

传送门

A. EhAb AnD gCd

签到。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/14 22:35:47
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n; cin >> n;
    cout << 1 << ' ' << n - 1 << '
';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

B. CopyCopyCopyCopyCopy

因为是严格上升子序列,所以每个数至多被选择一次。
最后答案即为数组中互不重复的数字个数。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/14 22:43:53
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n; cin >> n;
    vector <int> a(n);
    for(int i = 0; i < n; i++) cin >> a[i];
    sort(all(a));
    a.erase(unique(all(a)), a.end());
    cout << sz(a) << '
';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

C. Ehab and Path-etic MEXs

贪心。从叶子结点开始放置即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/14 22:50:27
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n;
vector <int> G[N];
int ans[N];
 
void run() {
    cin >> n;
    for(int i = 1; i < n; i++) {
        int u, v; cin >> u >> v;
        G[u].push_back(i);
        G[v].push_back(i);
    }
    memset(ans, -1, sizeof(ans));
    int now = 0;
    for(int i = 1; i <= n; i++) if(sz(G[i]) == 1){
        for(auto it : G[i]) if(ans[it] == -1) ans[it] = now++;   
    }
    for(int i = 1; i < n; i++) if(ans[i] == -1) ans[i] = now++;
    for(int i = 1; i < n; i++) cout << ans[i] << '
';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

D. Ehab the Xorcist

题意:
给出两个数(u,v,0leq u,vleq 10^{18})
构造长度最小的数组,使得数组中所有元素的异或和为(u),所有元素的和为(v)

思路:

  • 按二进制位来考虑,令数组中一个元素为(u),因为这些二进制位必须有,那么(vgeq u)才合法。
  • (d=v-u),考虑(d)的二进制位。若干(d)在第(k)位为(1),那么我们可以将其加在这一位上,或者加两倍在第(k-1)位上。因为要满足异或关系,所以不能改变二进制位的奇偶性,所以我们选择加两倍在(k-1)位上。若不能加则不合法。
  • 那么现在得到了(cnt[i])表示第(i)个二进制位为几倍,那么最终数组个数即为(max{cnt_i})。贪心得到数组元素即可。

代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/14 23:13:48
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 64;
 
int cnt[N], need[N];
 
void run() {
    ll u, v; cin >> u >> v;
    for(int i = 0; i < N; i++) if(u >> i & 1) ++cnt[i];
    if(u > v) {
        cout << -1 << '
';
        return;   
    }
    ll d = v - u;
    for(int i = N - 1; i >= 0; i--) if(d >> i & 1) {
        if(i) cnt[i - 1] += 2;
        else {
            cout << -1 << '
';
            return;
        }
    }
    vector <ll> ans;
    while(1) {
        bool ok = false;
        for(int i = 0; i < N; i++) if(cnt[i]) ok = true;   
        if(!ok) break;
        ll res = 0;
        for(int i = 0; i < N; i++) if(cnt[i]) {
            res += 1ll << i;
            --cnt[i];   
        }
        ans.push_back(res);
    }
    cout << sz(ans) << '
';
    for(auto it : ans) cout << it << ' ';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

E. Ehab's REAL Number Theory Problem

题意:
给出(a_{1,2,...,n},nleq 10^5,a_ileq 10^6),保证每个元素至多(7)个因子。
现在要从序列中选择长度最少的数,使得其乘积为完全平方数。

思路:

  • 由每个元素至多(7)个因子我们可以知道每个元素至多两个素因子,并且有如下几种形式:(p,p^2,pq,p^2q)
  • 乘积为完全平方数则等价于乘积的素因子指数都为偶数。据此显然(p^2q)(q)这种形式等价。
  • 对于(p^2)这种形式,我们可以直接单独考虑,那么最后就只剩下(p,pq)这两种形式。我们现在要选取最少的数,使得其乘积为完全平方数。也就是最后每个质因子的指数为(2)
  • 我们将(p)抽象为((1,p),pq)抽象为((p,q))。那么问题等价于求一个长度最小的环。因为环中每个点的度数为(2),也就是每个质因子的指数为(2)
  • 直接通过(dfs)树或者(bfs)树来求解的话时间复杂度为(O(n^2))。注意到一个环中最多只有(1)个数大于(1000),那么我们枚举所有不超过(1000)的数找环即可。

一点题外话:
最终通过(dfs)树或者(bfs)树来找环感觉有点迷。因为从一个点出发不能找出所有的环。(bfs)树还好,能找到起点所在的所有环;(dfs)树应该是找到所有依附于(dfs)树上的边的所有环,这样的话(dfs)的顺序不同找到的环也可能不同,感觉可能就存在随机性?
但代码我是直接(dfs)的,也通过了所有样例。
如果有大佬知道其中的一些原理,希望能不吝赐教。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/15 11:47:16
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;
 
int n;
int a[N];
int vis1[N];
map <pii, int> vis2;
vector <int> v[N];
int mp[N], tot;
 
int dep[N];
vector <int> G[N];
int ans;
 
void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    for(auto v : G[u]) if(v != fa) {
        if(dep[v] == 0) dfs(v, u);
        else if(dep[u] > dep[v]) {
            ans = min(ans, dep[u] - dep[v] + 1);   
        }
    }
}
 
void run() {
    cin >> n;
    bool ok = false;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        if(a[i] == 1) ok = true;
        int t = a[i], num = 0;
        for(int x = 2; 1ll * x * x <= a[i]; x++) {
            if(a[i] % x == 0) {
                int cnt = 0;
                while(a[i] % x == 0) a[i] /= x, ++cnt;
                if(cnt & 1) v[i].push_back(x);
                else ++num;
            }   
        }
        if(a[i] > 1) v[i].push_back(a[i]);
        if(num && !sz(v[i])) ok = true;
        a[i] = t;
    }
    if(ok) {
        cout << 1 << '
'; return;   
    }
    for(int i = 1; i <= n; i++) {
        if(sz(v[i]) == 1) {
            int from = 1, to = v[i][0];
            if(!mp[from]) mp[from] = ++tot;
            if(!mp[to]) mp[to] = ++tot;
            G[mp[from]].push_back(mp[to]);
            G[mp[to]].push_back(mp[from]);
            if(++vis1[v[i][0]] > 1) {
                cout << 2 << '
'; return;
            }
        }
        if(sz(v[i]) == 2) {
            int from = v[i][0], to = v[i][1];
            if(!mp[from]) mp[from] = ++tot;
            if(!mp[to]) mp[to] = ++tot;
            G[mp[from]].push_back(mp[to]);
            G[mp[to]].push_back(mp[from]);
            if(++vis2[MP(from, to)] > 1) {
                cout << 2 << '
'; return;   
            }
        }
    }
    ans = INF;
    for(int i = 1; i <= 1000; i++) if(mp[i]) {
        for(int j = 1; j <= tot; j++) dep[j] = 0;
        dfs(mp[i], 0);
    }
    if(ans == INF) ans = -1;
    cout << ans << '
';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

F. Ehab's Last Theorem

题意:
给出(n)个点,(m)条边的无向图。
现在要找到:

  • 刚好有(lceilsqrt{n} ceil)个点的独立集;
  • 长度至少为(lceilsqrt{n} ceil)的环。

找到其中一个即可。

思路:
(sq=lceilsqrt{n} ceil)

  • 环显然比直接找独立集好找,我们可以直接通过(dfs)树来找环。
  • 构建出(dfs)树后,若找不到长度不小于(sq)的环。我们将结点深度按照(\%(sq-1))进行分类。因为不存在环,那么显然现在任意同类的结点直接不会存在边。
  • 根据抽屉原理,必然会存在一类,其结点个数不小于(sq)。那么直接贪心找即可。

这个题也很巧妙,主要是(dfs)树的运用。题解中提到了一篇博客,写得挺细致的:传送门
代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/3/15 10:36:27
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, m, sq;
vector <int> G[N];
 
int dep[N];
vector <int> cyc;
void dfs(int u) {
    cyc.push_back(u);
    dep[u] = sz(cyc) - 1;
    for(auto v : G[u]) {
        if(dep[v] != -1) {
            if(dep[u] - dep[v] + 1 >= sq) {
                cout << 2 << '
';
                cout << dep[u] - dep[v] + 1 << '
';
                while(1) {
                    int now = cyc.back();
                    cout << now << ' ';
                    if(now == v) break;
                    cyc.pop_back();
                }
                exit(0);
            }         
        } else dfs(v);   
    }
    cyc.pop_back();
}
 
int cnt[N];
 
void run() {
    memset(dep, -1, sizeof(dep));
    cin >> n >> m;
    for(int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);   
    }
    sq = 1;
    while(1ll * sq * sq < n) ++sq;
    dfs(1);
    for(int i = 1; i <= n; i++) ++cnt[dep[i] % (sq - 1)];
    int Max = *max_element(cnt, cnt + n + 1);
    cout << 1 << '
';
    vector <int> ans;
    for(int i = 1; i <= n; i++) if(cnt[dep[i] % (sq - 1)] == Max) ans.push_back(i);
    ans.resize(sq);
    for(auto it : ans) cout << it << ' ';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
原文地址:https://www.cnblogs.com/heyuhhh/p/12502362.html