• Codeforces Round #506 (Div. 3) 题解


    [比赛链接]

             https://codeforces.com/contest/1029

    [比赛经历]

             本想靠DIV3上点分,没想到时差没有倒过来,最后三题收场,第二天SYSTEM TEST的时候D题还被卡常了,最后只加了1rating,算是一场比较失败的比赛吧

    [题解]

            A. Many Equal Substrings

            [算法]

                    我们可以找到这个字符串中最长的后缀 = 前缀的长度(记为T) , 那么 , 最后的答案就是S + S[T + 1..LEN] + S[T + 1..LEN] + .... + S[T + 1,LEN](共(k - 1)个S[T + 1,LEN]) , 最长后缀 = 前缀的长度我们可以通过kmp的next数组求出 , 当然 , 由于n比较小,朴素算法也是可以实现的

                    由于答案字符串的长度很短 , 我们也可以直接模拟 , 笔者在比赛时就采取了这种做法

                    时间复杂度 : O(N)

           [代码]

                 

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,k,len;
    string t,ans;
    
    template <typename T> inline void read(T &x)
    {
        int 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() 
    {
            
            cin >> n >> k;
            cin >> t;
            ans = t;
            int sum = 1 , now = 1;
            while (true)
            {
                    if (sum == k) break;
                    if (now == (int)ans.size()) ans += t; 
                    else if (now + n - 1 >= (int)ans.size()) 
                    {
                            if (now != (int)ans.size() && ans.substr(now,(int)ans.size() - now) != t.substr(0,(int)ans.size() - now)) now++;
                            else ans += t[(int)ans.size() - now]; 
                    } else if (ans.substr(now,n) == t.substr(0,n)) 
                    {
                            sum++;
                            now++;
                    } else now++;
            }
            cout<< ans << endl;
            
            return 0;
        
    }

                B. Creating the Contest

                [算法]

                       我们可以扫描一遍数组 , 当扫描到一个元素时 , 我们贪心地将该元素加入满足条件的 , 大小最大的组中 , 如果不存在满足条件的组就新建一个 , 最后的答案为最大的组的大小

                       时间复杂度 : O(N)

                [代码]

                         

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2 * 1e5 + 10;
    
    int n,tot;
    int g[MAXN],a[MAXN],sz[MAXN];
    
    template <typename T> inline void read(T &x)
    {
        int 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);
            for (int i = 1; i <= n; i++) read(a[i]);
            g[tot = 1] = a[1];
            sz[1] = 1;
            for (int i = 2; i <= n; i++)
            {
                    int pos = -1;
                    for (int j = 1; j <= tot; j++)
                    {
                            if (a[i] <= g[j] * 2)
                            {
                                    if (pos == -1 || sz[j] > sz[pos])
                                            pos = j;        
                            }
                    }        
                    if (pos != -1) 
                    {
                            g[pos] = a[i];
                            sz[pos]++;
                    } else 
                    {
                            g[++tot] = a[i];
                            sz[tot] = 1;
                    }
            }
            int ans = 0;
            for (int i = 1; i <= tot; i++) ans = max(ans,sz[i]);
            printf("%d
    ",ans);
            
            return 0;
        
    }

                    C. Maximal Intersection

                    [算法]

                            首先 , n条线段的交集长度为[Lmax,Rmin] , 其中Lmax为最靠右的左端点,Rmin为最靠左的右端点,若Lmax > Rmin , 说明这些线段无交集 

                            发现这个性质以后 , 我们可以枚举删去哪一条线段, 在剩余线段中找到最靠右的左端点和最靠左的右端点 ,用两者的差值更新答案,具体实现时,

                            我们可以记录前缀最值和后缀最值, 当然 , STL中的multiset和线段树等数据结构也是可以完成这个任务的

                           时间复杂度 : O(N) 或 O(N log N)

                   [代码]

                           

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 3e5 + 10;
    const int inf = 2e9;
    
    int n;
    int l[MAXN],r[MAXN],premn[MAXN],sufmn[MAXN],premx[MAXN],sufmx[MAXN];
    
    template <typename T> inline void read(T &x)
    {
        int 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);
            for (int i = 1; i <= n; i++) 
            {
                    read(l[i]);    
                    read(r[i]);
            }
            if (n == 1)
            {
                    printf("%d
    ",r[1] - l[1]);
                    return 0;
            }
            premx[0] = -inf;
            for (int i = 1; i <= n; i++) premx[i] = max(premx[i - 1],l[i]);
            sufmx[n + 1] = -inf;
            for (int i = n; i >= 1; i--) sufmx[i] = max(sufmx[i + 1],l[i]);
            premn[0] = inf;
            for (int i = 1; i <= n; i++) premn[i] = min(premn[i - 1],r[i]);
            sufmn[n + 1] = inf;
            for (int i = n; i >= 1; i--) sufmn[i] = min(sufmn[i + 1],r[i]);
            int ans = 0;
            for (int i = 1; i <= n; i++) ans = max(ans,min(premn[i - 1],sufmn[i + 1]) - max(premx[i - 1],sufmx[i + 1]));
            printf("%d
    ",ans);
            
            return 0;
        
    }

                        D.Concatenated Multiples

                        [算法]

                                不难发现 , 所有符合条件的二元组(i,j)都满足 : 10^(len(j)) * a[i] + a[j] 是k的倍数 ,我们不妨开10个std :: map , 其中,第m个map记录的是10^m * a[t] ( 1 <= t <= n)对k取模为V(0 <= V < k)的数的个数 , 然后我们枚举每一个数更新答案 , 最后 , 我们还需将答案减去(i,i)这样的

                                不合法的二元组

                                时间复杂度 : O(10Nlog(N))

                        [代码] 

                                此题时限很紧 , 注意优化常数 !

                                

    #include<bits/stdc++.h>
    using namespace std;
    #pragma GCC optimize("O2")
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast")
    const int MAXN = 2 * 1e5 + 10;
    typedef long long ll;
    
    int n;
    ll k,ans;
    map< ll,int > mp[11];
    ll a[MAXN];
    
    template <typename T> inline void read(T &x)
    {
        int 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 int len(ll n)
    {
            int ret = 0;
            while (n > 0)
            {
                    ret++;
                    n /= 10;
            }
            return ret;
    }
    inline ll Pow(int a,int n)
    {
            ll ret = 1;
            for (int i = 1; i <= n; i++) ret = 1ll * ret * a % k;
            return ret;
    }
    int main() 
    {
            
            read(n); read(k);
            for (int i = 1; i <= n; i++) read(a[i]);
            for (int i = 1; i <= n; i++)
            {
                    for (int j = 1; j <= 10; j++)
                    {
                            mp[j][1ll * Pow(10,j) * 1ll * a[i] % k]++;
                    }
            }
            for (int i = 1; i <= n; i++) if (mp[len(a[i])].count((k - a[i] % k) % k)) ans += mp[len(a[i])][(k - a[i] % k) % k];
            for (int i = 1; i <= n; i++)
            {
                    if ((1ll * Pow(10,len(a[i])) * a[i] % k + 1ll * a[i]) % k == 0)
                            ans--;
            }
            printf("%I64d
    ",ans);
            
            return 0;
        
    }

                         E. Tree with Small Distances

                         [算法]

                                 首先将所有的深度大于2的点加入一个堆中 , 每次我们找到深度最大的点 , 将这个点从堆中弹出 , 然后 , 我们将这个点的父节点和1号节点连一条边 , 在堆中删除所有与该节点父节点相连的边 

                                 当堆中没有元素时, 就得到了答案

                                 时间复杂度 : O(NlogN)

                         [代码]

                                 

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int inf = 2e9;
    
    int n,tot,ans;
    int head[MAXN],fa[MAXN],dep[MAXN];
    priority_queue< pair<int,int> > q;
    bool visited[MAXN];
    
    struct edge
    {
            int to,nxt;
    } e[MAXN << 1];
    
    template <typename T> inline void read(T &x)
    {
        int 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 addedge(int u,int v)
    {
            tot++;
            e[tot] = (edge){v,head[u]};
            head[u] = tot;
    }
    inline int dfs(int u,int par)
    {
            for (int i = head[u]; i; i = e[i].nxt)
            {
                    int v = e[i].to;
                    if (v == par) continue;
                    fa[v] = u;
                    dep[v] = dep[u] + 1;
                    dfs(v,u);
            }
    }
    
    int main() 
    {
            
            read(n);
            for (int i = 1; i < n; i++)
            {
                    int u,v;
                    read(u); read(v);
                    addedge(u,v);
                    addedge(v,u);
            }
            dfs(1,0);
            for (int i = 1; i <= n; i++)
            {
                    if (dep[i] > 2)
                            q.push(make_pair(dep[i],i));
            }
            while (!q.empty())
            {
                    int u = q.top().second;
                    q.pop(); 
                    if (visited[u]) continue;
                    visited[u = fa[u]] = true;
                    ans++;
                    for (int i = head[u]; i; i = e[i].nxt)
                    {
                            int v = e[i].to;
                            visited[v] = true;
                    }
            }
            printf("%d
    ",ans);
            
            return 0;
        
    }

                            F. Multicolored Markers

                            [算法]

                                      首先, 大长方形的边长一定是(a + b)的约数, 所以 , 我们可以从1到sqrt(a + b)枚举较小的那些因子(其中,sqrt表示开根号) , 求出(a + b)的所有约数

                                      既然我们要求至少有一种颜色的格子满足这些格子也能构成长方形 , 那么 , 我们可以同样用上述方法求出a和b的所有因子 

                                      为了方便讨论,我们假设所有红色颜色的格子能够构成长方形 

                                      然后 , 我们枚举大正方形的长d1 ,  用二分或Two Pointers求出小于d1的 , 最大的a的约数 , 如果((a + b) / d1 >= a / d2) , 我们就用(d1 + (a + b) / d1) * 2更新答案

                                      蓝色格子同理

                                      时间复杂度 : O(sqrt(a + b)) (其中 , sqrt表示开根号 )

                            [代码]

                                   

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXD = 1e5 + 10;
    typedef long long ll;
    const ll inf = 1e18;
    
    ll a,b,ans,lena,lenb;
    ll fa[MAXD],fb[MAXD];
    
    template <typename T> inline void read(T &x)
    {
        ll 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(a); read(b);
            ll tmp = a + b;
            for (ll i = 1; 1ll * i * i <= a + b; i++)
            {
                    if (tmp % i == 0)
                    {
                            fa[++lena] = i;
                            if (1ll * i * i != a + b) fa[++lena] = (a + b) / i;
                    }
            }
            for (ll i = 1; 1ll * i * i <= a; i++)
            {
                    if (a % i == 0)
                    {
                            fb[++lenb] = i;
                            if (1ll * i * i != a) fb[++lenb] = a / i;
                    }
            }
            sort(fb + 1,fb + lenb + 1);
            fb[++lenb] = inf;
            ans = inf;
            for (int i = 1; i <= lena; i++)
            {
                    ll d1 = fa[i];
                    int pos = lower_bound(fb + 1,fb + lenb + 1,d1) - fb;        
                    if (fb[pos] > d1 && pos == 1) continue;
                    if (fb[pos] > d1) pos--;
                    ll d2 = fb[pos];
                    if ((a + b) / d1 >= a / d2) ans = min(ans,2 * (d1 + (a + b) / d1));
            }
            lenb = 0;
            for (ll i = 1; 1ll * i * i <= b; i++)
            {
                    if (b % i == 0)
                    {
                            fb[++lenb] = i;    
                            if (1ll * i * i != b) fb[++lenb] = b / i;
                    }
            }
            sort(fb + 1,fb + lenb + 1);
            fb[++lenb] = inf;
            for (int i = 1; i <= lena; i++)
            {
                    ll d1 = fa[i];
                    int pos = lower_bound(fb + 1,fb + lenb + 1,d1) - fb;        
                    if (fb[pos] > d1 && pos == 1) continue;
                    if (fb[pos] > d1) pos--;
                    ll d2 = fb[pos];
                    if ((a + b) / d1 >= b / d2) ans = min(ans,2 * (d1 + (a + b) / d1));
            }
            printf("%I64d
    ",ans);
            
            return 0;
        
    }

                    [总结]

                    1. 这次比赛的失利不仅是因为时差的问题 , 我认为 , 更多的还是我的基本功不够扎实 , 值得反思

                    2. 突然发现打比赛也是一种提高水平的好方法 , 每次比赛都能发现自己的薄弱点并订正试题 , 查漏补缺 , 以后要多参加这些比赛 , 不仅提高了能力 , 而且 , 英语水平也能得到提高

                    3. 离noip2018只剩两个月了 , 在剩下的两个月中 , 我还需更加努力 , 调整好心态 , 争取最后取得理想的成绩

  • 相关阅读:
    Winform Treeview 的按需加载
    Dynamic CRM 2013学习笔记(十)客户端几种查询数据方式比较
    Dynamic CRM 2013学习笔记(九)CrmFetchKit.js介绍:Fetchxml、多表联合查询, 批量更新
    Dynamic CRM 2013学习笔记(八)过滤查找控件 (类似省市联动)
    iOS Programming
    Hello Socket
    解决ARC的循环引用问题
    解决Eclipse下不自动拷贝apk到模拟器问题( The connection to adb is down, and a severe error has occured)
    解决Android NDK 报jxxx编译找不到
    做一个创建cocos2d-x新项目的shell脚本
  • 原文地址:https://www.cnblogs.com/evenbao/p/9538327.html
Copyright © 2020-2023  润新知