zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 96 ABCDE 题解(详解)

    A. Number of Apartments

    题意:用3、5、7凑数,若能凑出给出方案,不能则输出-1。

    思路:观察发现除了1 2 4凑不到以外其他都凑得到。那么关于方案的话,既然其他数都凑得到,我们就可以用dp的思想每次试探着来,若减去当前数还是个可以凑得到的就继续减直到等于0。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define endl '
    '
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 1e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    ll all[3] = {7,5,3};
    ll Map[2000];
    ll cnt[10];
    
    int main()
    {
        int kase;
        cin>>kase;
        Map[1] = 1, Map[2] = 1, Map[4] = 1;
        while(kase--)
        {
            ll n = read();
            mem(cnt,0);
            if(Map[n])
            {
                cout<<-1<<endl;
                continue;
            }
            while(n)
            {
                rep(i,0,2) if(n-all[i]>=0&&!Map[n-all[i]])
                {
                    cnt[all[i]]++;
                    n -= all[i];
                    break;
                }
            }
            cout<<cnt[3]<<' '<<cnt[5]<<' '<<cnt[7]<<endl;
        }
        return 0;
    }
    
    

    B. Barrels

    题意:有n个无限容量的水桶,现在各含a[i]的水,现在可以随便k次,问最大最小值差的最大值。

    思路:水题,从次大的水桶开始倒k桶,全部倒进最大的那一桶。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define endl '
    '
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 2e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    ll a[maxn];
    
    int main()
    {
        int kase;
        cin>>kase;
        while(kase--)
        {
            ll n = read(), k = read();
            rep(i,1,n) a[i] = read();
            sort(a+1,a+1+n);
            int p = 1;
            ll cnt = 1;
            for(int i=n-1; i>=1&&cnt<=k; i--)
            {
                a[n] += a[i];
                cnt++;
            }
            cout<<a[n]<<endl;
        }
        return 0;
    }
    
    

    C. Numbers on Whiteboard

    题意:每次可以把任意两个数a,b替换成(lceil {(a+b)/2} ceil),可以操作n-1次,问最后剩下的一个数能达到的最小值是多少。并且输出每一步操作。

    思路:从后面大的开始,先把a[n] a[n-2]变成a[n-1],再把两个a[n-1]结合变成1个a[n-1],然后就可以一路从a[n-3]往前平推,每次都会使得值-1。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define endl '
    '
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 2e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    
    typedef struct Ans
    {
        ll a;
        ll b;
    }A;
    A ans[maxn];
    
    
    int main()
    {
        int kase;
        cin>>kase;
        while(kase--)
        {
            ll n = read();
            ll k = n-1;
            if(n==2)
            {
                cout<<2<<endl;
                cout<<1<<' '<<2<<endl;
                continue;
            }
            ans[1].a = n;
            ans[1].b = n-2;
            ans[2].a = n-1;
            ans[2].b = n-1;
            int p = 2;
            ll cur = n-1;
            per(i,n-3,1)
            {
                ans[++p].a = cur;
                ans[p].b = i;
                cur = (cur+i+1)/2;
            }
            cout<<cur<<endl;
            rep(i,1,p) cout<<ans[i].a<<' '<<ans[i].b<<endl;
        }
        return 0;
    }
    
    

    D. String Deletion

    题意:给你一个01串,每一次操作必须先删掉任意一个位置,然后删除掉最长相同前缀。问最多能维持多少次这个操作。

    思路:既然每次操作是对一个相同前缀下手,那我们就把每一块相同数所组成的联通块看成一个整体。同时记录他们的长度。
    如1110010就可以看成
    111 00 1 0
    写成联通块(长度表示)
    3 2 1 1
    然后我们发现,会使得我们操作变少的是联通块长度为1的,我们现在想让1尽量的维持下去,即不让他在每次操作前减完自身使得要牺牲下一个联通块。
    首先考虑到如果一个数大于1,那么“删除”这一步减自己就好了,不浪费别的。
    而如果一个数等于1, 那我们就要考虑从它后面(轮到它当前缀时)找一些大于2的数(找2的话一减又多出个1来),这样就可以让它维持下去,删除前缀时就可以减掉当前的1而不影响后面一个。而找不到的话,那就只能减去当前这个1,然后再牺牲下一个联通块了(下一个联通块变成新的前缀)。
    主要的思想就是上面说的,现在考虑怎么实现“在后面找一个大于2的数”,如果每个位置都往后找,那就是(O(n^2))的时间复杂度,肯定不行。
    我们发现当前i位置往后,若找到某个位置j来删除,那么在i+1位置,肯定也是从j开始往后找的,也就是前j-1个位置既然都不满足i位置,那么肯定也不满足i+1位置。这样我们只需要用双指针走一遍这个数组即可。时间复杂度(O(2n))

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define endl '
    '
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 2e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    string s;
    ll block[maxn];
    int p = 0;
    ll solve()
    {
        int q = 1;
        ll ans = 0;
        bool flag = 0;
        rep(i,1,p)
        {
            if(flag)
            {
                ans++;
                i += 1;
                continue;
            }
            if(block[i]>1) ans++;
            else
           {
                while(q<i||(q<=p&&block[q] <= 1)) q++;
                if(q>p)
                {
                    flag = 1;
                    ans++;
                    i += 1;
                }
                else
                {
                    block[q]--;
                    ans++;
                }
           }
        }
        return ans;
    }
    
    int main()
    {
        int kase;
        cin>>kase;
        while(kase--)
        {
            p = 0;
            ll n = read();
            string s;
            cin>>s;
            block[++p] = 1;
            rep(i,1,n-1)
            {
                if(s[i]==s[i-1]) block[p]++;
                else block[++p] = 1;
            }
            cout<<solve()<<endl;
        }
        return 0;
    }
    
    

    E. String Reversal

    题意: 给一个字符串,每次可以相邻位置交换,问最少多少次可以使得字符串变成原来的颠倒字符串。

    思路:显然有比直接一步步交换过去更优的策略。
    比如acbac,我们想让第一个a变到最后一个位置去,完全不需要第一个位置的a动,只需要最靠近右边的a和c交换即可,一步到位。
    所以策略就是每次都让最靠近右边的,和当前字符相同的字符移动就好。
    但是这样会有个问题,就是有些位置被移动过,它左边的数再经过它往右交换时,距离就要减去这个空位。那怎么维护这个东西呢?
    我们把这个“空位”产生的影响描述出来就是,一开始找到第一个位置的最靠右的相同字符,位置为p1,丢到最后,距离是n-p1。
    然后第二个位置最靠右相同字符的位置p2, 若p2<p1,即p1这个空位对p2产生影响了,那就是n-p2-1。同理若p3<p2, 那就是n-p3-2。
    所以就只需要统计p位置后面有多少空位即可,然后减去这个数。
    这个时候树状数组的作用就来了。
    为了方便,我们反过来看,从最后开始往前丢数,一开始是p1-1, 然后若p2>p1, 就p2-1-1,其次是p3-2-1(后面的-1是到1的距离,再减的就是空位个数)。所以我们的空位对计数是负贡献,把一开始[1,n]的区间每个位置都置为1, 一旦产生一个位置p产生空位,就在p这个位置-1,这样前缀和即表示(p-空位个数),每次的贡献就是前缀和-1。

    view code
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include <queue>
    #include<sstream>
    #include <stack>
    #include <set>
    #include <bitset>
    #include<vector>
    #define FAST ios::sync_with_stdio(false)
    #define abs(a) ((a)>=0?(a):-(a))
    #define sz(x) ((int)(x).size())
    #define all(x) (x).begin(),(x).end()
    #define mem(a,b) memset(a,b,sizeof(a))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,n,a) for(int i=n;i>=a;--i)
    #define endl '
    '
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    const int maxn = 2e5+200;
    const int inf=0x3f3f3f3f;
    const double eps = 1e-7;
    const double pi=acos(-1.0);
    const int mod = 1e9+7;
    inline int lowbit(int x){return x&(-x);}
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
    inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
    inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
    inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
    inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
    int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
    
    ll n;
    string s;
    queue<ll> q[50];
    ll c[maxn];
    
    inline int id(int p)
    {
        return s[p-1] - 'a' + 1;
    }
    
    inline void add(int p, ll val)
    {
        for(int i=p; i<=n; i+=lowbit(i)) c[i] += val;
    }
    
    inline ll ask(int p)
    {
        ll ans = 0;
        for(int i=p; i>=1; i-=lowbit(i)) ans += c[i];
        return ans;
    }
    
    int main()
    {
        n = read();
        cin>>s;
        rep(i,1,n) q[id(i)].push(i), add(i,1);
        ll ans = 0;
        per(i,n,1)
        {
            int pos = q[id(i)].front();
            q[id(i)].pop();
            ans += ask(pos)-1; add(pos, -1);
        }
        cout<<ans<<endl;
        return 0;
    }
    
    

  • 相关阅读:
    docker 方式安装gitlab时,项目的clone地址及项目文件列表地址为机器名的问题解决办法
    CPU流水线
    Element中el-form嵌套el-table双击编辑提交检验
    java基础知识
    C#多线程下载
    mysql优化
    C++ 算法(一)
    前端vue 的面试总结 以及答案以及前端技术点面试
    C# 组合任务
    C# List去重DistinctBy扩展
  • 原文地址:https://www.cnblogs.com/Bgwithcode/p/13805677.html
Copyright © 2011-2022 走看看