zoukankan      html  css  js  c++  java
  • Codeforces Round #630 (Div. 2)

    传送门

    A. Exercising Walk

    显然横纵坐标我们可以分开考虑。
    假设只考虑横坐标,若(x_2 ot ={x_1}),那么向左/向右走可以互相抵消,然后只能往一个方向走;若(x_2=x_1),那么就不能向左/向右走。
    纵坐标同理。
    只需要check一下最终位置是否在矩形内即可。
    赛场上写的代码有些复杂:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/3/31 21:38:57
     */
    #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 a, b, c, d; cin >> a >> b >> c >> d;
        int x, y; cin >> x >> y;
        int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2;
        int w = r2 - r1, h = c2 - c1;
        if(w) {
            int t = min(a / w, b / w);
            a -= t * w, b -= t * w;
            int tt = min(a, b);
            a -= tt, b -= tt;          
        }
        if(a > x - r1 || b > r2 - x) {
            cout << "NO" << '
    ';
            return;   
        }
        if(h) {
            int t = min(c / h, d / h);
            c -= t * h, d -= t * h;
            int tt = min(c, d);
            c -= tt, d -= tt;          
        }
        if(c > y - c1 || d > c2 - y) {
            cout << "NO" << '
    ';
            return;   
        }
        cout << "YES" << '
    ';
        return;
    }
     
    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. Composite Coloring

    因为(a_ileq 1000)且为合数,容易证明只需要前面(11)个质数即可构造出所有的(a_i)
    染色的话随便染就行。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/3/31 22:01:11
     */
    #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 = 1000 + 5;
     
    int n;
    int a[N], col[N];
    int primes[N], tot;
    bool vis[N];
     
    void init() {
        for(int i = 2; i < N; i++) {
            if(!vis[i]) primes[++tot] = i;
            for(int j = i * i; j < N; j += i) vis[j] = true;   
        }
    }
     
    void run() {
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        vector <vector <int>> c, p;
        c.resize(12); p.resize(n + 1);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= 11; j++) {
                if(a[i] % primes[j] == 0) {
                    c[j].push_back(i);
                    p[i].push_back(j);
                }
            }
        }
        memset(col, -1, sizeof(col));
        for(int i = 1; i <= 11; i++) {
            for(auto it : c[i]) {
                if(col[it] == -1) {
                    col[it] = i;
                    break;
                }   
            }
        }
        for(int i = 1; i <= n; i++) if(col[i] == -1) col[i] = p[i][0];
        map <int, int> mp; int num = 0;
        for(int i = 1; i <= n; i++) {
            if(!mp[col[i]]) mp[col[i]] = ++num;
            col[i] = mp[col[i]];
        }
        cout << num << '
    ';
        for(int i = 1; i <= n; i++) cout << col[i] << " 
    "[i == n];
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        int T; cin >> T;
        while(T--) run();
        return 0;
    }
    

    C. K-Complete Word

    贪心搞即可。
    容易发现将长度为(n)的串划分为(displaystylefrac{n}{k})个长度为(k)的串,并且每个串都相等且都为回文串。
    那么对长度为(k)的串暴力找代价最小的回文串就行。
    详见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/3/31 22:23:34
     */
    #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 = 2e5 + 5;
     
    int n, k;
    int cnt[N][26];
    char s[N];
     
    void run() {
        cin >> n >> k;
        cin >> (s + 1);
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < 26; j++) {
                cnt[i][j] = 0;
            }
        }
        for(int i = 1; i <= k; i++) {
            for(int j = i; j <= n; j += k) {
                ++cnt[i][s[j] - 'a'];
            }   
        }
        int l = 1, r = k;
        int ans = 0;
        int d = n / k;
        while(l < r) {
            int res = INF;
            for(int i = 0; i < 26; i++) {
                res = min(res, 2 * d - cnt[l][i] - cnt[r][i]);
            }
            ans += res;
            ++l, --r;
        }
        if(l == r) {
            int res = INF;
            for(int i = 0; i < 26; i++) {
                res = min(res, d - cnt[l][i]);
            }   
            ans += res;
        }
        cout << ans << '
    ';
    }
     
    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;
    }
    

    D. Walk on Matrix

    题意:
    假设现在有一个(ncdot m)的矩阵,每个位置的权值为(a_{i,j})。现在从((1,1))出发要到达((n,n)),每次只能往下走或者往右走,代价为:当前价值(x)(a_{i,j})(&),即(x& a_{i,j})
    现在有个(dp)代码:

    显然这个(dp)是不正确的。
    现在要求构造一个矩阵,使得(dp)跑出来的结果与最大值相差为(k)
    限制条件为:(n,mleq 500,a_{i,j}leq 3cdot 10^5,kleq 10^5)

    思路:

    • 我们考虑诱导(dp)结果为(0),此时最大值为(k),这样方便构造。
    • 注意到(k)(a_{i,j})的取值范围,我们考虑(ngeq 2,mgeq 2)(k>0)的情况:现在得到最大的二进制为(lim),最大权值为((lim*2)-1),那么直接构造(a_{2,2}=k+lim,a_{1,2}=lim,a_{2,1}=a_{2,3}=a_{3,2}=k)
    • 按以上构造可以得出(dp_{2,2}=lim),但是最终结果为(0),因为(lim& k=0)。但最大的答案应该是(k)
    • (n==1||m==1)(k=0)的情况随便构造即可。

    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/3/31 22:49:29
     */
    #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 k;
    int a[4][4];
     
    void run() {
        cin >> k;
        if(k == 0) {
            cout << 1 << ' ' << 1 << '
    ' << 0 << '
    ';
            return;   
        }
        int lim = 1;
        while(lim < 3e5) lim <<= 1;
        lim >>= 2;
        int MAX = (lim << 1) - 1;
        cout << 3 << ' ' << 3 << '
    ';
        a[1][1] = MAX;
        a[2][1] = k;
        a[1][2] = lim;
        a[2][2] = lim + k;
        a[2][3] = a[3][2] = (MAX ^ lim);
        a[3][3] = MAX;
        for(int i = 1; i <= 3; i++) {
            for(int j = 1; j <= 3; j++) {
                cout << a[i][j] << ' ';
            }   cout << '
    ';
        }
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    E. Height All the Same

    题意:
    现有大小为(ncdot m)的矩阵,每个格子上可以任意选择一个([L,R])的数。现在可以对该矩形执行任意次数以下两种操作:

    • 选择一个格子,令(a_{i,j}+=2)
    • 选择两个相邻格子,让他们都加上(1)

    如果最终能够使得所有格子上面数值相同,那么就称该矩阵为完美的。
    现在问每个格子选择的数值在([L,R])范围内时有多少完美矩阵。

    思路:

    • 从每个权值的奇偶性出发:操作(1)不会改变奇偶性,操作(2)则相当于一个“翻转”操作:(0 ightarrow 1,1 ightarrow 0)
    • 那么问题等价于给定一个(01)矩阵,是否存在一种操作方案,使得所有数为(0)或者为(1)
    • 那么有一个重要的观察:如果矩形中有偶数个(0)或者(1),那么此时可以通过操作(2)使得所有数都相同。
    • 现在考虑(ncdot m)的奇偶性:
      • (ncdot m)为奇数,那么会发现不论怎么放,至少会存在偶数个数个(0)或者(1)。此时随便放即可。
      • (ncdot m)为偶数,(0,1)的个数必须都为偶数。若都为奇数,那么操作(2)并不会改变((奇,奇))的局面,因为通过操作(2)要么不改变(0,1)个数,要么使得个数增加/减少(2),不改变((奇,奇))的局面。

    现在回到这个题,假设(x)([L,R])中偶数的个数,(y)为奇数的个数。
    因为我们选择的数在([L,R])范围内,实际上通过思考我们发现只跟奇偶性相关。当(ncdot m)为奇数时,我们随便放置就行;当(ncdot m)为偶数时,我们必须放置偶数个奇数以及偶数个偶数,那么枚举放置偶数的个数:(displaystylesum_{i=0,2,cdots,ncdot m}x^iy^{ncdot m-i}{nmchoose i})
    我们容易发现这跟牛顿二项式定理有关。赛场上脑袋短路,忘记如何求解这个式子。。
    其实这个式子就等于(displaystyle ((x+y)^{ncdot m}+(x-y)^{ncdot m}) / 2)
    这貌似是数学中常用的一个技巧。
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/3/31 23:52:41
     */
    #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, MOD = 998244353, inv2 = (MOD + 1) >> 1;
    int qpow(ll a, ll b) {
        ll res = 1;
        a %= MOD;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
     
     
    void run() {
        ll n, m, L, R;
        cin >> n >> m >> L >> R;
        int even = R / 2, odd = (R + 1) / 2;
        even -= (L - 1) / 2, odd -= L / 2;
        int res = qpow(even + odd, n * m);
        if((n * m) & 1) cout << res << '
    ';
        else {
            res += qpow(max(even, odd) - min(even, odd), n * m);
            res %= MOD;
            res = 1ll * res * inv2 % MOD;
            cout << res << '
    ';
        }
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    赛场上貌似很多人直接矩阵快速幂过的,其实这个很好想,根据上面的思考,我们得出最后的结果只与放置奇数个奇数/偶数和放置偶数个奇数/偶数有关。
    (dp[i][2])表示前(i)个数,放置了奇数个/偶数个奇数/偶数,不妨考虑放置的是奇数。那么转移为:

    • (dp[i][1]=dp[i-1][0]cdot O+dp[i-1][0]cdot E);
    • (dp[i][0]=dp[i-1][1]cdot O+dp[i-1][0]cdot E)

    那么当(ncdot m)为奇数时,答案为(dp[ncdot m][0]+dp[ncdot m][1]);否则,答案为(dp[ncdot m][0])
    这个过程我们用矩阵快速幂进行优化即可。
    代码略。

    F. Independent Set

    题意:
    给出一颗树(G=(V,E)),现在要求

    [sum_{E' ot ={emptyset}subset E}w(G'[E']) ]

    其中(G'[E'])为图(G)关于边集(E')的边生成子图,(w(G'[E']))是指该图独立集的个数。

    思路:

    • 考虑对每个结点进行染色,(dp)时枚举每条边是否断开。显然可以分情况讨论:

      • (u)不染色时,那么边((u,v))无论是否断开,都可以从(v)染色或者不染色两种情况进行转移。
      • (u)染色时,若边((u,v))断开,那么(v)可染色也可不染色;边((u,v))没有断开,那么(v)不能染色。
    • 因为要从边生成子图中找独立集,也就是每个染色的点至少会有一条边与之相连。那么上述两种情况断开时儿子结点都可以染色,但要排除儿子结点为单独一个点的情况。

    • (dp[u][2])(u)结点为根节点时,所有儿子结点都没有边与之相连的情况。显然这种情况会被算入(dp[u][1],dp[u][0])

    • 那么我们只需要在上述转移中将(dp[v][2])(dp[v][1])中减去即可。

    这题主要就是要注意一个单独的点不能染色的情况,而这种情况是容易计算且含于其它(dp)状态中的,所以转移时直接排除(减去)这种情况即可。
    具体转移细节见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/1 20:29:05
     */
    #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 = 3e5 + 5, MOD = 998244353;
    
    int n;
    vector <int> G[N];
    int dp[N][3];
    
    void dfs(int u, int fa) {
        dp[u][0] = dp[u][1] = dp[u][2] = 1;
        for(auto v : G[u]) if(v != fa) {
            dfs(v, u);
            dp[u][0] = 1ll * dp[u][0] * (2ll * dp[v][0] + 2 * dp[v][1] - dp[v][2] + MOD) % MOD;
            dp[u][1] = 1ll * dp[u][1] * (2ll * dp[v][0] + dp[v][1] - dp[v][2] + MOD) % MOD;
            dp[u][2] = 1ll * dp[u][2] * (1ll * dp[v][0] + dp[v][1] - dp[v][2] + MOD) % MOD;
        }   
    }
    
    void run() {
        cin >> n;
        for(int i = 1; i < n; i++) {
            int u, v; cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);   
        }
        dfs(1, 0);
        int ans = ((ll)dp[1][0] + dp[1][1] - dp[1][2] + MOD - 1) % MOD;
        cout << ans << '
    ';
    }   
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    
  • 相关阅读:
    vue+element的el-menu组件实现路由跳转及当前项的设置
    继承与多态
    八、使用for解决简单的问题
    六、Js数组的使用方法
    五、JS操作HTML方法
    四、初步入门JS的用法
    三、html总结
    二、表格<table>的使用
    一、初步接触html,基本标签和ul、ol的用法
    运算符的分类
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12612378.html
Copyright © 2011-2022 走看看