• CF1178比赛题解


    A题
    小学抽屉问题,
    答案就是(max(n - s,n - t) + 1)
    复杂度(O(T))
    代码:

    #include <bits/stdc++.h>
    
    int T, n, m, i, j, k;
    int a[2];
    
    int main() {
        scanf("%d",&T);
        while(T--) {
            scanf("%d %d %d",&n,&a[0],&a[1]);
            printf("%d
    ",std::max(n - a[0],n - a[1]) + 1);  
        }
    }
    
    

    B题
    我们维护一个(vector)数组(v),其中(v_i)存的是字母(i)所出现的位置。
    那么因为我们是依次( ext{push_back})的,
    那么第(i)个字母的位置其实就是(v_{i - 1})(因为下标从0开始)。
    我们查的时候只需要将(t_i)遍历一遍然后取个(max)就好。
    而访问一个下标又是(O(1))的操作,
    所以总复杂度为(O(m * max(|t_i|))
    代码:

    #include <bits/stdc++.h> 
    
    const int maxn = 2e5 + 10;
    const int maxm = 5e4 + 10;
    
    inline void cmax(int& x,int y) {
        if(x < y)
            x = y;
    }
    
    char s[maxn];
    int n, m, i, j, k; 
    int cnt[27];
    std::vector<int> v[27];
    
    int main() {
        int n;  scanf("%d",&n);  
        scanf("%s",s + 1);
        int l = strlen(s + 1);
        for(int i = 1;i <= l;i++) {
            int c = s[i] - 'a' + 1;
            v[c].push_back(i);
        }    
        scanf("%d",&m);
        while(m--) {
            static char t[maxn];  
            scanf("%s",t + 1);
            int l = strlen(t + 1);  
            memset(cnt,0,sizeof(cnt));
            for(int i = 1;i <= l;i++) 
                cnt[ t[i] - 'a' + 1 ]++;
            int ans = 0;
            for(int i = 1;i <= l;i++) {
                int c = t[i] - 'a' + 1;
                cmax(ans,v[c][ cnt[c] - 1 ]);		
            }
            printf("%d
    ",ans);
        }
        return 0;
    } 
    
    

    C题
    我们把所有操作全部分离,
    然后排个序。
    然后先处理不下降的,
    赋值的时候如果左端点没有赋值过那就去(n - x)(一定保证小于左边一个),
    否则就使用上一次的赋值(排过序,所以一定不降)。
    剩下的如果有空隙那就表示一定是下降序列,
    那么直接填就好。
    于是这道题就做完了。
    复杂度(O(n))

    #include <bits/stdc++.h>
    
    const int maxn = 1010;
    const int maxm = 1010;
    const int inf = 0x3f3f3f3f;
    
    template<class Tp> inline void read(Tp& res) {
        res = 0;  char ch = getchar();  bool neg = 0;
        while(!isdigit(ch))
            neg |= ch == '-', ch = getchar();
        while(isdigit(ch))
            res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
        if(neg)
            res = -res; 
    }
    inline void cmin(int& x,int y) {
        if(x > y)
            x = y;
    }
    inline int _abs(int x) {
        return x < 0 ? -x : x;
    }
    
    int n, m, i, j, k;  
    int a[maxn];  
    std::vector<std::pair<int,int> > q1, q2;
    
    int main() {
        read(n);  read(m);
        for(int i = 1, op, l, r;i <= m;i++) {
            read(op);  read(l);  read(r);
            if(op)
                q1.push_back(std::make_pair(l,r));
            else
                q2.push_back(std::make_pair(l,r));
        }
        std::sort(q1.begin(),q1.end());
        std::sort(q2.begin(),q2.end());     
        int v;
        for(auto i : q1) {
            int l = i.first, r = i.second;
            if(!a[l])
                v = n - l;
            for(int j = l;j <= r;j++)
                a[j] = v;    
        }
        for(int i = 1;i <= n;i++)
            if(!a[i])
                a[i] = n - i;
        for(auto i : q2) {
            int l = i.first, r = i.second, tmp = a[l];  
            bool ok = 0;
            for(int j = l;j <= r;j++)
                if(a[j] < tmp) {
                    ok = 1;
                    break;
                }
            if(!ok)
                return puts("NO"), 0;    
        }        
        puts("YES");
        for(int i = 1;i <= n;i++)
            printf("%d ",a[i] + 5010);
        return 0;   
    }
    

    D题
    又是一道典型的恶意评分。
    我们思考一下冒泡排序的原理,每次只对两个数进行操作可以有同样的效果。
    这时可以发现一点,对于一个(a_i),它一定要比前面的都小才可能到达指定的位置上去。
    那么我们用线段树维护一下最小值就结束了...
    结束了?对,结束了...
    复杂度(O(n log n))
    代码:

    #include <bits/stdc++.h>
    
    const int maxn = 3e5 + 10;
    const int inf = 0x3f3f3f3f;
    
    template<class Tp> inline void read(Tp& res) {
        res = 0;  char ch = getchar();  bool neg = 0;
        while(!isdigit(ch))
            neg |= ch == '-', ch = getchar();
        while(isdigit(ch)) 
            res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
        if(neg)
            res = -res; 
    }
    inline int _min(int a,int b) { return a < b ? a : b; }
    inline void cmin(int& a,int b) {
        if(a > b)
            a = b;
    }
    inline void cmax(int& a,int b) {
        if(a < b)
            a = b;  
    }
    
    int n, m, i, j, k, T, mx;  
    int a[maxn], b[maxn], c[maxn], pos[maxn], t[maxn << 2];
    std::queue<int> q[maxn];  
    
    inline bool check() {
        for(int i = 1;i <= mx;i++)
            if(c[i] != 0)
                return 0;
        return 1;    
    }
    
    inline void push_up(int u) {
        t[u] = _min(t[u << 1],t[u << 1 | 1]);
    }
    void build(int l,int r,int u) {
        if(l == r) 
            return t[u] = a[l], void(); 
        int mid = (l + r) >> 1;
        build(l,mid,u << 1);
        build(mid + 1,r,u << 1 | 1);
        push_up(u);  
    }
    int query(int ql,int qr,int l,int r,int u) {
        if(ql <= l && r <= qr) 
            return t[u];
        int mid = (l + r) >> 1, res = inf;
        if(ql <= mid)
            cmin(res,query(ql,qr,l,mid,u << 1));
        if(mid < qr)
            cmin(res,query(ql,qr,mid + 1,r,u << 1 | 1));
        return res;  
    }
    void modify(int m,int l,int r,int u,int v) {
        if(l == m && r == m)
            return t[u] = v, void();
        int mid = (l + r) >> 1;
        if(m <= mid)
            modify(m,l,mid,u << 1,v);
        else
            modify(m,mid + 1,r,u << 1 | 1,v);
        push_up(u);        
    }
    
    int main() {
        read(T);
        while(T--) {
            read(n);  mx = 0;
            for(int i = 1;i <= n;i++)
                c[i] = 0;  
            for(int i = 1;i <= n;i++) {
                read(a[i]);
                cmax(mx,a[i]);
                c[ a[i] ]++;
            }
            for(int i = 1;i <= n;i++)
                read(b[i]), cmax(mx,b[i]), c[ b[i] ]--;     
            if(!check()) {
                puts("NO");
                continue; 
            } 
            for(int i = 1;i <= n;i++)
                q[ a[i] ].push(i);  
            for(int i = 1;i <= n;i++) {
                pos[i] = q[ b[i] ].front();
                q[ b[i] ].pop();
            } 
            build(1,n,1);  bool flag = 1;
            for(int i = 1;i <= n;i++) {
                int p = pos[i];  
                if(query(1,p,1,n,1) != b[i]) {  
                    flag = 0;  
                    puts("NO");   
                    break;
                }
                modify(p,1,n,1,inf);
            }
            if(flag)
                puts("YES");
        }
        return 0;
    }
    

    E题
    树形dp。
    设u为当前节点,
    (f[fa_u] = S_{fa_u} + sz_{u} + n + S_{ch_u})
    (f[u] = S_{ch_u} + 2 * n - sz_u + S_{fa_u})
    可以推出(f[u] = f[fa_u] + n - sz_u * 2)
    转移即可,

    #include <bits/stdc++.h>
    
    typedef long long ll;
    const int maxn = 2e5 + 10;  
    
    int cnte, n, m, i, j, k;
    int sz[maxn], hd[maxn], ver[maxn << 1], nxt[maxn << 1];
    ll f[maxn], ans;     
    
    inline void adde(int u,int v) {
        ver[++cnte] = v;  nxt[cnte] = hd[u];
        hd[u] = cnte;  return;   
    }
    inline void cmax(ll& a,ll b) {
        if(a < b)
            a = b;
    }
    
    void dfs1(int u,int pa) {
        sz[u] = 1;
        for(int i = hd[u];~i;i = nxt[i]) {
            int v = ver[i];
            if(v == pa)
                continue;
            dfs1(v,u);  
            sz[u] += sz[v];
        }
        f[1] += sz[u];
    }
    
    void dfs2(int u,int pa) {
        for(int i = hd[u];~i;i = nxt[i]) {
            int v = ver[i];
            if(v == pa)
                continue;
            f[v] = f[u] + n - 2 * sz[v];
            cmax(ans,f[v]);
            dfs2(v,u);   
        }
    }
    
    int main() {
        memset(hd,-1,sizeof(hd));
        scanf("%d",&n);
        for(int i = 1, u, v;i < n;i++) {
            scanf("%d %d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        dfs1(1,0);
        dfs2(1,0);   
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Go学习(5):集合
    Go学习(4):数组和切片
    Go学习(3):分支循环
    Go学习(2):基本语法
    Go学习(1):简介和配置
    input输入框只能输入数字而且开头不能为零
    JS 显示周 几和 月 日
    IntelliJ Idea 跳出括号并且光标移到末尾的快捷键
    不可小视的String字符串
    PrintWriter中的write与println方法居然就是这些区别
  • 原文地址:https://www.cnblogs.com/Sai0511/p/11173529.html
Copyright © 2020-2023  润新知