zoukankan      html  css  js  c++  java
  • Codeforces Round #535(div 3) 简要题解

    Problem A. Two distinct points

    [题解]

            显然 , 当l1不等于r2时 , (l1 , r2)是一组解

            否则 , (l1 , l2)是一组合法的解

            时间复杂度 : O(1)

    [代码]

           

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    int main()
    {
        
        int T;
        read(T);
        while (T--)
        {
                int l1 , r1 , l2 , r2;
                read(l1); read(r1); read(l2); read(r2);
                if (l1 != r2) cout<< l1 << ' ' << r2 << '
    ';
                else cout<< l1 << ' ' << l2 << '
    ';
        }
        return 0;
        
    }

    Problem B. Divisors of Two Integers

    [题解]

             首先 , 给定序列中的最大数一定是x和y中的一个数

             将该数的所有因子从序列中删除一次 , 剩余数中的最大数即为另一个数

             时间复杂度 : O(M) (取M = 10 ^ 4)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 10010
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n;
    int d[MAXN] , cnt[MAXN];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    int main()
    {
            
            read(n);
            int fst = 0 , sec = 0;
            for (int i = 1; i <= n; i++) 
            {
                    read(d[i]);
                    if (d[i] > fst) fst = d[i];
                    ++cnt[d[i]];
            }
            for (int i = 1; i <= fst; i++) 
                    if (fst % i == 0) --cnt[i];
            for (int i = (int)1e4; i >= 1; i--)
            {
                    if (cnt[i])
                    {
                            sec = i;
                            break;        
                    }        
            }    
            cout<< fst << ' ' << sec << '
    ';
            
            return 0;
        
    }

    Problem C. Nice Garland

    [题解]

           通过观察发现 , 答案一定是一个以"R" , "G" , "B"三个字符所形成的一个排列为循环节循环得到的字符串

           枚举排列 , 计算最优解 , 即可

           时间复杂度 : O(N)

    [代码]

           

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int inf = 1e9;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n;
    char s[MAXN] , t1[MAXN] , t2[MAXN] , t3[MAXN] , t4[MAXN] , t5[MAXN] , t6[MAXN];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    int main()
    {
        
            scanf("%d" , &n);
            scanf("%s" , s + 1);
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t1[i] = 'R';
                    if (i % 3 == 2) t1[i] = 'G';
                    if (i % 3 == 0) t1[i] = 'B';
            }
            int stp = 0 , ans = 0 , mstp = inf;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t1[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 1;
            }
            
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t2[i] = 'R';
                    if (i % 3 == 2) t2[i] = 'B';
                    if (i % 3 == 0) t2[i] = 'G';
            }
            stp = 0;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t2[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 2;
            }
            
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t3[i] = 'B';
                    if (i % 3 == 2) t3[i] = 'R';
                    if (i % 3 == 0) t3[i] = 'G';
            }
            stp = 0;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t3[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 3;
            }
            
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t4[i] = 'B';
                    if (i % 3 == 2) t4[i] = 'G';
                    if (i % 3 == 0) t4[i] = 'R';
            }
            stp = 0;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t4[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 4;
            }
            
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t5[i] = 'G';
                    if (i % 3 == 2) t5[i] = 'R';
                    if (i % 3 == 0) t5[i] = 'B';
            }
            stp = 0;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t5[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 5;
            }
            
            for (int i = 1; i <= n; i++)
            {
                    if (i % 3 == 1) t6[i] = 'G';
                    if (i % 3 == 2) t6[i] = 'B';
                    if (i % 3 == 0) t6[i] = 'R';
            }
            stp = 0;
            for (int i = 1; i <= n; i++)        
                    if (s[i] != t6[i]) ++stp;
            if (stp < mstp)
            {
                    mstp = stp;
                    ans = 6;
            }
            
            cout<< mstp << '
    ';
            if (ans == 1)
            {
                    for (int i = 1; i <= n; i++) putchar(t1[i]);
                    cout<< '
    ';
            }
            if (ans == 2)
            {
                    for (int i = 1; i <= n; i++) putchar(t2[i]);
                    cout<< '
    ';
            }
            if (ans == 3)
            {
                    for (int i = 1; i <= n; i++) putchar(t3[i]);
                    cout<< '
    ';
            }
            if (ans == 4)
            {
                    for (int i = 1; i <= n; i++) putchar(t4[i]);
                    cout<< '
    ';
            }
            if (ans == 5)
            {
                    for (int i = 1; i <= n; i++) putchar(t5[i]);
                    cout<< '
    ';
            }
            if (ans == 6)
            {
                    for (int i = 1; i <= n; i++) putchar(t6[i]);
                    cout<< '
    ';
            }
            
            return 0;
        
    }

    Problem D.  Diverse Garland

    [题解]

             简单贪心即可

             时间复杂度 : O(N)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 10;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n , cnt;
    char s[MAXN];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    int main()
    {
            
            scanf("%d" , &n);
            scanf("%s" , s + 1);
            map<char , int> mp;
            mp.clear();
            for (int i = 2; i < n; i++) 
            {
                    if (s[i] != s[i - 1]) continue;
                    mp.clear();
                    mp[s[i - 1]]++; mp[s[i + 1]]++;
                    if (mp['R'] && mp['G']) 
                    {
                            s[i] = 'B';
                            ++cnt;
                    } else if (mp['R'] && mp['B']) 
                    {
                            s[i] = 'G';
                            ++cnt;
                    } else if (mp['B'] && mp['G']) 
                    {
                            s[i] = 'R';
                            ++cnt;
                    } else if (mp['R']) 
                    {
                            s[i] = 'G';
                            ++cnt;
                    } else if (mp['G']) 
                    {
                            s[i] = 'B';
                            ++cnt;
                    } else 
                    {
                            s[i] = 'R';
                            ++cnt;
                    }
            }
            if (s[n] == s[n - 1])
            {
             

              int i = n;
              mp.clear();
              ++mp[s[n - 1]];
              if (mp['R'])
              {
                 s[i] = 'G';
                 ++cnt;
              } else if (mp['G'])
              {
                  s[i] = 'B';
                  ++cnt;
              } else
              {
             s[i] = 'R';
             ++cnt;
             }

             }

            cout<< cnt << '
    ';
            for (int i = 1; i <= n; i++) putchar(s[i]);
            printf("
    ");
            
            return 0;
        
    }

    Problem E. Array and Segments

    [题解]

           Easy Version :

           枚举序列中的最大值和最小值的出现位置 , 然后枚举每一条线段 , 贪心地选择所有覆盖了最小值出现位置的线段

           时间复杂度 : O(N ^ 2M)

           [代码]

                  

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 310
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n , m , ans;
    int a[MAXN] , l[MAXN] , r[MAXN];
    vector< int > fans;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void solve(int x , int y)
    {
            int tx = a[x] , ty = a[y]; 
            vector< int > res;
            res.clear();
            for (int i = 1; i <= m; i++)
            {
                    if (l[i] <= x && r[i] >= x) continue;
                    if (l[i] <= y && r[i] >= y)
                    {
                            res.push_back(i);
                            --ty;
                    }
            }        
            if (tx - ty > ans)
            {
                    ans = tx - ty;
                    fans.clear();
                    for (unsigned i = 0; i < res.size(); i++) fans.push_back(res[i]);
            }
    }
    
    int main()
    {
            
            read(n); read(m);
            for (int i = 1; i <= n; i++) read(a[i]);
            for (int i = 1; i <= m; i++)
            {
                    read(l[i]);
                    read(r[i]);
            }
            for (int i = 1; i <= n; i++)
            {
                    for (int j = 1; j <= n; j++)
                    {
                            if (i != j)
                                    solve(i , j);
                    }
            }
            cout<< ans << '
    ';
            cout<< (int)fans.size() << '
    ';
            for (unsigned i = 0; i < (int)fans.size(); i++) cout<< fans[i] << ' ';
            cout<< '
    ';
            
            return 0;
        
    }

                Hard Version :

                          我们可以先选择所有线段           

                          那么 , 问题就转化为 , 选择一些区间进行操作 , 使得[li , ri]每个数增加1 , 最大化序列中的最大值 - 最小值

                          考虑枚举最大值出现的位置 , 显然 , 我们可以贪心地选择所有覆盖了该位置的线段

                          那么我们就可以使用扫描线算法 :

                          从1-n按顺序枚举最大值出现的位置i , 考虑所有以i为左端点的线段 , 我们选择这些线段进行操作 , 然后考虑所有以i为右端点的线段 , 取消对这些线段的操作

                          维护一棵支持区间修改 , 询问区间最大 / 最小值的线段树即可

                          时间复杂度 : O(NMlogN)

                  [代码]

                          

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 10;
    
    #pragma GCC optimize(2)
    #define rint register int
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n , m;
    int l[MAXN] , r[MAXN] , val[MAXN];
    vector< int > s[MAXN] , e[MAXN];
    bool tag[MAXN];
    
    struct Segment_Tree
    {
            struct Node
            {
                  int l , r , tag;
                  pair<int , int> value; 
            } a[MAXN << 2];
            inline void build(int index , int l , int r)
            {
                    a[index].l = l , a[index].r = r;
                    a[index].tag = 0;
                    if (l == r)
                    {
                            a[index].value = make_pair(val[l] , val[l]);
                            return;
                    }
                    int mid = (l + r) >> 1;
                    build(index << 1 , l , mid);
                    build(index << 1 | 1 , mid + 1 , r);
                    update(index);
            }
            inline void update(int index)
            {
                    a[index].value.first = min(a[index << 1].value.first , a[index << 1 | 1].value.first);
                    a[index].value.second = max(a[index << 1].value.second , a[index << 1 | 1].value.second);
            }
            inline void pushdown(int index)
            {
                    a[index << 1].value.first += a[index].tag;
                    a[index << 1 | 1].value.first += a[index].tag;
                    a[index << 1].value.second += a[index].tag;
                    a[index << 1 | 1].value.second += a[index].tag;
                    a[index << 1].tag += a[index].tag;
                    a[index << 1 | 1].tag += a[index].tag;
                    a[index].tag = 0;
            }
            inline void modify(int index , int l , int r , int val)
            {
                    if (a[index].l == l && a[index].r == r)
                    {
                            a[index].value.first += val;
                            a[index].value.second += val;
                            a[index].tag += val;
                            return;
                    }
                    pushdown(index);
                    int mid = (a[index].l + a[index].r) >> 1;
                    if (mid >= r) modify(index << 1 , l , r , val);
                    else if (mid + 1 <= l) modify(index << 1 | 1 , l , r , val);
                    else
                    {
                            modify(index << 1 , l , mid , val);
                            modify(index << 1 | 1 , mid + 1 , r , val);
                    }
                    update(index);
            }
            inline pair<int , int> query()
            {
                    return a[1].value;
            } 
    } SGT;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    
    int main()
    {
            
            read(n); read(m);
            for (rint i = 1; i <= n; i++) read(val[i]);
            SGT.build(1 , 1 , n);
            for (rint i = 1; i <= m; i++)
            {
                    read(l[i]);
                    read(r[i]);
                    s[l[i]].push_back(r[i]);
                    e[r[i]].push_back(l[i]);
                    SGT.modify(1 , l[i] , r[i] , -1);
            }
            int mx = 0 , loc = 0;
            for (rint i = 1; i <= n; i++)
            {
                    for (unsigned j = 0; j < s[i].size(); j++)
                            SGT.modify(1 , i , s[i][j] , 1);
                    pair<int , int> tmp = SGT.query();
                    if (tmp.second - tmp.first > mx) 
                    {
                            mx = tmp.second - tmp.first;
                            loc = i;    
                    }        
                    for (unsigned j = 0; j < e[i].size(); j++)
                            SGT.modify(1 , e[i][j] , i , -1);
            }
            cout<< mx << '
    ';
            vector< int > res;
            for (int i = 1; i <= m; i++)
            {
                    if (l[i] > loc || r[i] < loc)
                            res.push_back(i);        
            }
            cout<< (int)res.size() << '
    ';
            for (unsigned i = 0; i < res.size(); i++) cout<< res[i] << ' ';
            cout<< '
    ';
            
            return 0;
        
    }

    Problem F. MST Unification

    [题解]

            首先用kruskal算法求出这个图的任意一棵最小生成树

            枚举不在这颗最小生成树上的每一条边(u , v , w)

            若加入这条边 , 则形成了一个环 , 若环上的边权除这条边外的最大值 = w , 那么说明可以用这条边替换环上权值 = w的边 , 我们需要将这条边的权值加一

            倍增即可

            时间复杂度 : O((N + M)logN)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int MAXN = 2e5 + 10;
    const int MAXLOG = 20;
    
    struct Edge
    {
            int x,y;
            long long w;
    } edge[MAXN << 1];
    
    int T,n,m,i;
    long long val;
    vector< pair<int,long long> > e[MAXN];
    bool on_mst[MAXN];
    int fa[MAXN],anc[MAXN][MAXLOG],dep[MAXN];
    long long mx[MAXN][MAXLOG];
    bool not_unique;
    
    inline bool cmp(Edge a,Edge b) { return a.w < b.w; }
    inline int get_root(int x)
    {
            if (fa[x] == x) return x;
            return fa[x] = get_root(fa[x]);
    }
    inline void kruskal()
    {
            int i,x,y,sx,sy;
            long long w;
            for (i = 1; i <= n; i++) fa[i] = i;
            for (i = 1; i <= m; i++) on_mst[i] = false;
            sort(edge+1,edge+m+1,cmp);
            for (i = 1; i <= m; i++)
            {
                    x = edge[i].x;
                    y = edge[i].y;
                    w = edge[i].w;
                    sx = get_root(x); 
                    sy = get_root(y);
                    if (sx != sy)
                    {
                            on_mst[i] = true;
                            val += w;
                            fa[sx] = sy;
                            e[x].push_back(make_pair(y,w));
                            e[y].push_back(make_pair(x,w));    
                    }    
            }    
    }
    inline void build(int u)
    {
            int i,v;
            for (i = 1; i < MAXLOG; i++) 
            {
                    anc[u][i] = anc[anc[u][i-1]][i-1];
                    mx[u][i] = max(mx[u][i-1],mx[anc[u][i-1]][i-1]);
            }
            for (i = 0; i < e[u].size(); i++)
            {
                    v = e[u][i].first;
                    if (anc[u][0] != v)
                    {
                            dep[v] = dep[u] + 1;
                            anc[v][0] = u;
                            mx[v][0] = e[u][i].second;
                            build(v);                        
                    }
            }
    }
    inline long long get(int x,int y)
    {
            int i,t;
            long long ans = 0;
            if (dep[x] > dep[y]) swap(x,y);
            t = dep[y] - dep[x];
            for (i = 0; i < MAXLOG; i++)
            {
                    if (t & (1 << i))
                    {
                            ans = max(ans,mx[y][i]);
                            y = anc[y][i];
                    }
            }
            if (x == y) return ans;
            for (i = MAXLOG - 1; i >= 0; i--)
            {
                    if (anc[x][i] != anc[y][i])
                    {
                            ans = max(ans,max(mx[x][i],mx[y][i]));
                            x = anc[x][i];
                            y = anc[y][i];
                    }
            }
            return max(ans,max(mx[x][0],mx[y][0]));
    }
    int main() 
    {
            
          scanf("%d%d",&n,&m);
          val = 0;
          not_unique = false;
          for (i = 1; i <= n; i++) 
          {
                  dep[i] = 0;
                  e[i].clear();
                  memset(anc[i],0,sizeof(anc[i]));
                  memset(mx[i],0,sizeof(mx[i]));
          }
          for (i = 1; i <= m; i++) scanf("%d%d%lld",&edge[i].x,&edge[i].y,&edge[i].w);
          kruskal();
          build(1);
          int ans = 0;
          for (i = 1; i <= m; i++) 
          {
                if (!on_mst[i]) 
                    ans += (get(edge[i].x,edge[i].y) == edge[i].w);
          }
          cout<< ans << '
    ';
          
            return 0;
        
    }
  • 相关阅读:
    CF1091E
    jzoj5703
    CF1109F
    杂题
    CF1194F
    杂题
    个人作业1-数组(二维数组)
    第三周-学习进度条
    构建之法阅读笔记02
    个人作业1-数组(续1)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10316766.html
Copyright © 2011-2022 走看看