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 << '\n';
            else cout<< l1 << ' ' << l2 << '\n';
    }
    return 0;
    
}

Problem B. Divisors of Two Integers

[题解]

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

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

扫描二维码关注公众号,回复: 5055330 查看本文章

         时间复杂度 : 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 << '\n';
        
        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 << '\n';
        if (ans == 1)
        {
                for (int i = 1; i <= n; i++) putchar(t1[i]);
                cout<< '\n';
        }
        if (ans == 2)
        {
                for (int i = 1; i <= n; i++) putchar(t2[i]);
                cout<< '\n';
        }
        if (ans == 3)
        {
                for (int i = 1; i <= n; i++) putchar(t3[i]);
                cout<< '\n';
        }
        if (ans == 4)
        {
                for (int i = 1; i <= n; i++) putchar(t4[i]);
                cout<< '\n';
        }
        if (ans == 5)
        {
                for (int i = 1; i <= n; i++) putchar(t5[i]);
                cout<< '\n';
        }
        if (ans == 6)
        {
                for (int i = 1; i <= n; i++) putchar(t6[i]);
                cout<< '\n';
        }
        
        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 << '\n';
        for (int i = 1; i <= n; i++) putchar(s[i]);
        printf("\n");
        
        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 << '\n';
        cout<< (int)fans.size() << '\n';
        for (unsigned i = 0; i < (int)fans.size(); i++) cout<< fans[i] << ' ';
        cout<< '\n';
        
        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 << '\n';
        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() << '\n';
        for (unsigned i = 0; i < res.size(); i++) cout<< res[i] << ' ';
        cout<< '\n';
        
        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 << '\n';
      
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/10316766.html