zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 216 A~F 题解

    本场链接:AtCoder Beginner Contest 216

    A - Signed Difficulty

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    int main()
    {
        int x,y;scanf("%d.%d",&x,&y);
        printf("%d",x);
        if(y <= 2)  puts("-");
        else if(y >= 7) puts("+");
        return 0;
    }
    

    B - Same Name

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    const int N = 1005;
    string s[N],t[N];
    
    int main()
    {
        Angel_Dust;
        int n;cin >> n;
        forn(i,1,n) cin >> s[i] >> t[i];
        forn(i,1,n) forn(j,1,i - 1) if(s[i] == s[j] && t[i] == t[j])    return cout << "Yes
    ",0;
        cout << "No
    ";
        return 0;
    }
    

    C - Many Balls

    如果一开始就塞入60个B,那么在倒数第(i)个后面插入一个A会产生 (2^{i - 1})的贡献,如此根据 (n) 的二进制分解构造即可.

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    int main()
    {
        ll n;scanf("%lld",&n);
        string res;
        forr(i,0,59)
        {
            if(n >> i & 1)  res.push_back('A');
            res.push_back('B');
        }
    
        res.pop_back();
        
        cout << res << endl;
        return 0;
    }
    

    D - Pair of Balls

    直接模拟.

    维护:每一列数,某个颜色如果当前是末尾元素则他来自哪一列,某个元素是否已经被删除,以及每个颜色当前的个数(在末尾位置).

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    const int N = 2e5+7;
    vector<int> E[N],ID[N];
    int cnt[N];
    bool del[N];
    
    
    int main()
    {
        int n,m;scanf("%d%d",&n,&m);
        set<pii> st;
        forn(i,1,m)
        {
            int k,x;scanf("%d",&k);
            forn(j,1,k) scanf("%d",&x),E[i].push_back(x);
            reverse(E[i].begin(),E[i].end());
            ++cnt[E[i].back()];
            ID[E[i].back()].push_back(i);
        }
    
        forn(i,1,n) if(cnt[i])  st.insert({cnt[i],-i});
    
        while(!st.empty())
        {
            auto _ = (*--st.end());st.erase(_);
            
            int c = _.x,delcol = -_.y;
            if(del[delcol]) continue;
            del[delcol] = 1;
            if(c == 1)  return puts("No"),0;
            int p1 = ID[delcol][0],p2 = ID[delcol][1];
            E[p1].pop_back();E[p2].pop_back();
            if(!E[p1].empty())
            {
                ++cnt[E[p1].back()];
                ID[E[p1].back()].push_back(p1);
            }
            if(!E[p2].empty())
            {
                ++cnt[E[p2].back()];
                ID[E[p2].back()].push_back(p2);
            }
            if(!E[p1].empty()) st.insert({cnt[E[p1].back()],-E[p1].back()});
            if(!E[p2].empty()) st.insert({cnt[E[p2].back()],-E[p2].back()});
        }
    
        puts("Yes");
        return 0;
    }
    

    E - Amusement Park

    由于 (k) 很大,不能直接一步一步的去减,考虑加速每次减1的过程:当前取出的 (a) ,如果有多个合并.一直减到什么时候会变化过程?把 (a) 减到仅小于他的那个元素 (b) 的时候,此时需要把两组数进行合并.如此可以维护一个堆:堆内元素是<val,cnt>的形式.

    每次取出堆顶的元素 (<a,c>),记上一个元素是 (b) ,考虑将 (c) 个元素一起减,那么每次会减掉 (c),一共可以减 (cir = min(k / cnt(↓),a - b)) 轮,会导致 (k -= cir * c),同时 $ a -= cir $.这一段每个 (a)会从 (a) 减到 (a - cir),所以是一个等差数列求和,一共有 (c) 个,答案累加即可.

    其次,如果 (a) 在减少之后与 (b) 相同,则意味着这一轮已经进行完毕,可以和 (b) 进行合并,将堆内两个元素进行合并即可.如果没有,说明 (k)即使用完了也做不到使的 (a)(b) 相同,此时如果还有剩余,就把最后的 (k) 也榨干求贡献.

    特别的,为了方便实现,在堆内加入一个 (<0,0>).因为比 (0) 更小的没有意义.

    注意各种地方都会爆数据, (a[i] leq 2*10^9)很麻烦.

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    const int N = 1e5+7;
    int a[N];
    
    int main()
    {
        int n,k;scanf("%d%d",&n,&k);
        forn(i,1,n) scanf("%d",&a[i]);
        sort(a + 1,a + n + 1);
        
        priority_queue<pii> pq;pq.push({0,0});
        forn(i,1,n)
        {
            int j = i;
            while(j + 1 <= n && a[j + 1] == a[i])   ++j;
            pq.push({a[j],j - i + 1});
            i = j;
        }
    
        ll res = 0;
    
        while(!pq.empty())
        {
            auto _ = pq.top();pq.pop();
            int a = _.x,c = _.y;
            if(a == 0)  break;
            int b = pq.top().x;
            int cir = min(k / c,a - b),r = a,l = a - cir + 1;
            if(l <= r)   res += c * 1ll * (l * 1ll + r) * (r * 1ll - l + 1) / 2;
            k -= 1ll * c * cir;
            a -= cir;
            if(a == b)  c += pq.top().y,pq.pop(),pq.push({b,c});
            else
            {
                res += 1ll * k * a;
                k = 0;
            }
            if(!k)  break;
        }
        printf("%lld
    ",res);
        return 0;
    }
    

    F - Max Sum Counting

    如果单纯的考虑子集这个条件,想到即使使用 SOSDP 这样的科技做子集求和也只能做到 (O(n2^n)) 的复杂度,而这个题可以承受的是 (O(n^2)) 显然这样不是一个合理的方向.考虑从 (max_{i in S} A_i)入手:可以想到次序无关,所以把所有二元组按照 (a) 不降的顺序排序.现在考虑统计答案:

    枚举 (i) 并且要求 (a_i) 就是左端的最大值,即剩下的元素只能在([1,i - 1]) 中选择.现在条件可以写成这样: (sum_{j in S} B_j + B_i leq A_i).可以再换写成 (sum_{j in S}B_j leq A_i - B_i).现在问题就等价于是在求([1,i - 1])中选出若干下标,使得他们的和小于某个限制的方案数:每个元素要么选要么不选,这就是一个经典的01背包求方案数问题,直接做即可.

    于是有个问题,因为01背包的复杂度是 (O(nC)),其中 (C) 是值域大小,如果直接去做的话会导致复杂度是 (O(n^3)) 的,但是 (C) 真的有必要是所有元素的值域吗?因为限制是 (A_i - B_i) 所以限制其实是 (O(n)) 大小的.于是可以只做 (C = N) 的部分,因为限制只那么多,这样复杂度就是 (O(n^2))的了.做完dp之后对答案求前缀和就可以得到小于等于的方案数了.直接统计答案即可.

    #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 x first
    #define y second
    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
    
    const int N = 5005,MOD = 998244353;
    int a[N],b[N],f[N][N],d[N];
    
    bool cmp(int x,int y)
    {
        if(a[x] != a[y])    return a[x] < a[y];
        return b[x] < b[y];
    }
    
    int main()
    {
        int n;scanf("%d",&n);
        forn(i,1,n) d[i] = i;
        forn(i,1,n) scanf("%d",&a[i]);
        forn(i,1,n) scanf("%d",&b[i]);
    
        sort(d + 1,d + n + 1,cmp);
    
        f[0][0] = 1;
        forn(i,1,n)
        {
            forn(j,0,N - 1)
            {
                f[i][j] = f[i - 1][j];
                if(j >= b[d[i]])   f[i][j] = (f[i][j] * 1ll + f[i - 1][j - b[d[i]]]) % MOD;
            }
        }
    
        forn(i,0,n) forn(j,1,N - 1) f[i][j] = (1ll * f[i][j] + f[i][j - 1]) % MOD;
    
        int res = 0;
        forn(i,1,n)
        {
            if(a[d[i]] < b[d[i]]) continue;
            res = (res + 1ll * f[i - 1][a[d[i]] - b[d[i]]]) % MOD;
        }
        printf("%d
    ",res);
        return 0;
    }
    
    
  • 相关阅读:
    软考过后
    最近
    软考复习初体验
    再看提高班
    C语言深入学习系列 字节对齐&内存管理
    C++ 阶段一(已完成)
    小弟,开博学习了!!
    [学习心得] 我总结的进制转换
    《深入浅出设计模式》一书学习(.net版—简单工厂)
    安装mysql 获得 mysql.h 建立C接口
  • 原文地址:https://www.cnblogs.com/HotPants/p/15205023.html
Copyright © 2011-2022 走看看