zoukankan      html  css  js  c++  java
  • Codeforces Round #737 (Div. 2) A~E 题解

    本场链接:Codeforces Round #737 (Div. 2)

    闲话

    做的时候把C的条件转错了白做一个多小时.最后E由于假了所以就不写了,有兴趣自己补吧.

    A. Ezzat and Two Subsequences

    考虑平均值:最大值所在的组,会因为放入别的数而变小.每个数都需要在一个组,不难想到使最大值单独成一个组即可.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    
    const int N = 1e5+7;
    ll a[N];
    
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
            int n;scanf("%d",&n);
            forn(i,1,n) scanf("%lld",&a[i]);
            sort(a + 1,a + n + 1);
            ll sum = 0;forn(i,1,n - 1)  sum += a[i];
            printf("%.18lf
    ",a[n] + 1.0 * sum / (n - 1));
        }
        return 0;
    }
    
    

    B. Moamen and k-subarrays

    一段数可以在一起不动,当且仅当他们是连续增大的.为了方便不妨先把所有数映射成他们的rank,如此条件就等价于一段连续增大的段.求出段数(cnt)(cnt leq k)时可以划分.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    
    const int N = 1e5+7;
    int a[N],d[N];
    
    bool cmp(int x,int y)
    {
        return a[x] < a[y];
    }
    
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
            int n,k;scanf("%d%d",&n,&k);
            forn(i,1,n) scanf("%d",&a[i]),d[i] = i;
            sort(d + 1,d + n + 1,cmp);
            forn(i,1,n) a[i] = d[i];
    
            int cnt = 0;
            forn(i,1,n)
            {
                int j = i;
                while(j + 1 <= n && a[j + 1] == a[j] + 1)    ++j;
                ++cnt;
                i = j;
            }
            if(cnt <= k)    puts("yes");
            else puts("no");
        }
        return 0;
    }
    
    

    C. Moamen and XOR

    原条件可以看做是有两种情况:要么相同要么严格大于.如果严格大于说明存在某一位(k)在此位上左部严格大于右部,这样只能是1/0的情形,同时前半部分完全相同,后半部分随意填充.

    前半部分完全相同,分奇偶考虑组合数,后半部分随意填显然是(2)的长度幂次.如此,枚举一个前缀相同,直到某一位产生严格大即可.(其实还能注意到(n)为奇数的时候可以直接有一个答案公式).

    在实现的时候写(0)下标会好写一些.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    
    const int MOD = 1e9+7;
    ll qpow(ll a,ll b,ll MOD)
    {
        ll res = 1;
        while(b)
        {
            if(b & 1)   res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
            int n,k;scanf("%d%d",&n,&k);
            if(k == 0) 
            {
                puts("1");
                continue;
            }
            if(n == 1)
            {
                printf("%lld
    ",qpow(2,k,MOD));
                continue;
            }
            if(n % 2 == 1)
            {
                ll res = qpow(2,n - 1,MOD) + 1;
                res = qpow(res,k,MOD);
                printf("%lld
    ",res);
            }
            else
            {
                ll res = qpow(2,k - 1,MOD);
                res = qpow(res,n,MOD);
                ll _ = qpow(2,n - 1,MOD);
                _ = ((_ - 1) % MOD + MOD) % MOD;
                _ = qpow(_,k,MOD);
                res = (res + _) % MOD;
                forn(j,1,k - 1)
                {
                    ll nxt = ((qpow(2,n - 1,MOD) - 1) % MOD + MOD) % MOD;
                    nxt = qpow(nxt,j,MOD);
                    ll oth = qpow(2,n,MOD);
                    oth = qpow(oth,k - j - 1,MOD);
                    nxt = nxt * oth % MOD;
                    res = (res + nxt) % MOD;
                }
                printf("%lld
    ",res);
            }
        }
        return 0;
    }
    
    

    D. Ezzat and Grid

    数据范围很吊比,先不看那么多,考虑直接做:每一行有删和不删两种决策,而且由于删这个操作不好表达信息,考虑计算保留行数:

    • 状态:(f[i])表示前([1,i])行中最多可以保留的行数.但是有个问题,这样没有前面状态在哪一行有(1)可以贴上去的信息,如此:(f[i][j])表示前([1,i])行中,强制保留第(i)行且第(i)行第(j)列有(1)的最多保留数.
    • 入口:全部置(0)即可.
    • 转移:考虑第(i)行保留下来的转移方式:若第(k)行的第(j)列与(i)行的第(j)列同时存在,则可以从(f[k][j])转移到(f[i][j]).
    • 出口:枚举最大值即可.

    这样直接做显然复杂度会达到(O(n^2)).可以发现(j)维的转移事实上等价于在区间上加和以及求区间上的最值.所以可以开一个线段树维护(j)维,将每一层一段(1)看做是一个区间求最值的操作(由前面的行转移而来),每层做完之后对本行做覆盖.

    但是本题还需要求方案,常规来说,只需记录(f[i])的转移前驱是谁即可,即维护一个(succ[i])表示(f[i])是由那个状态转移来的.在线段树上维护最值得同时维护最值来源的下标即可找到上一个保留的行具体是谁,如此即可找出在最优方案中具体保留了哪些行.即可将答案输出.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define l first
    #define r second
    
    const int N = 1e6+7,INF = 1e9;
    const pii PZ = {0,-1};
    vector<int> vals;
    vector<pii> E[N];
    int PID[N],st[N];
    
    struct Node
    {
    	int l,r;
        pii v,lazy;
    }tr[N * 4];
    
    
    inline int link(int x)
    {
        return lower_bound(vals.begin(),vals.end(),x) - vals.begin() + 1;
    }
    
    void pushup(int u)
    {
        tr[u].v = max(tr[u << 1].v,tr[u << 1 | 1].v);
    }
    
    void pushdown(int u)
    {
        auto& lf = tr[u << 1],&s = tr[u],&rt = tr[u << 1 | 1];
        if(s.lazy == PZ)    return ;
        s.v = max(s.v,s.lazy);
        lf.lazy = max(lf.lazy,s.lazy);lf.v = max(lf.v,lf.lazy);
        rt.lazy = max(rt.lazy,s.lazy);rt.v = max(rt.v,rt.lazy);
        s.lazy = PZ;
    }
    
    void build(int u,int l,int r)
    {
        if(l == r)  tr[u] = {l,r,PZ,PZ};
        else
        {
            int mid = l + r >> 1;
            tr[u] = {l,r};
            build(u << 1,l,mid),build(u << 1 | 1,mid + 1,r);
            pushup(u);
        }
    }
    
    void modify(int u,int l,int r,pii& v)
    {
        if(tr[u].l >= l && tr[u].r <= r)
        {   
            tr[u].v = max(tr[u].v,v);
            tr[u].lazy = max(tr[u].lazy,v);
            return ;
        }
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid)    modify(u << 1,l,r,v);
        if(r > mid)     modify(u << 1 | 1,l,r,v);
        pushup(u);
    }
    
    pii query(int u,int l,int r)
    {
        if(tr[u].l >= l && tr[u].r <= r)    return tr[u].v;
        int mid = tr[u].l + tr[u].r >> 1;pii res = PZ;
        pushdown(u);
        if(l <= mid)    res = max(res,query(u << 1,l,r));
        if(r > mid)     res = max(res,query(u << 1 | 1,l,r));
        return res;
    }
    
    int main()
    {
        memset(PID,-1,sizeof PID);
        int n,m;scanf("%d%d",&n,&m);
        forn(i,1,m)
        {
            int p,l,r;scanf("%d%d%d",&p,&l,&r);
            vals.push_back(l);vals.push_back(r);
            E[p].push_back({l,r});
        }
        
        sort(vals.begin(),vals.end());
        vals.erase(unique(vals.begin(),vals.end()),vals.end());
    
        forn(i,1,n) for(auto& _ : E[i]) _.l = link(_.l),_.r = link(_.r);
        build(1,1,N - 1);
    
        forn(i,1,n)
        {
            if(E[i].empty())    continue;
            pii mx = PZ;
            for(auto& _ : E[i]) mx = max(mx,query(1,_.l,_.r));
            // modify(1,1,N - 1,mx);
            PID[i] = mx.r;
            ++mx.l;
            mx.r = i;
            for(auto& _ : E[i]) modify(1,_.l,_.r,mx);
        }
    
        pii res = query(1,1,N - 1);
        int cur = res.r;
        while(cur != -1)
        {   
            st[cur] = 1;
            cur = PID[cur];
        }
    
        printf("%d
    ",n - res.l);
        forn(i,1,n) if(!st[i])  printf("%d ",i);
        puts("");
        return 0;
    }
    
  • 相关阅读:
    hdu 3577 线段树
    hdu 5316 Magician 线段树
    POJ3468 本来是一道线段树
    hdu 3183 st表
    hdu 5285 BestCoder Round #48 ($) 1002 种类并查集
    hdu 5282 序列计数
    zoj 2432 模板LCIS
    hdu 1052 贪心
    Angular实践----定制你自己的指令
    Angular实践----理解数据绑定过程
  • 原文地址:https://www.cnblogs.com/HotPants/p/15142721.html
Copyright © 2011-2022 走看看