• Codeforces Round #764 (Div. 3)


    Codeforces Round #764 (Div. 3)

    VP直播回放:https://www.bilibili.com/video/BV1GT4y127WQ (A-D)

    A - Plus One on the Subset

    讲了一堆,最后只要最大-最小就行了。

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 60;
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            int n;
            cin>>n;
            int x;
            int maxx=0;
            int minn=1e9;
            for(int i=1;i<=n;i++)
            {
                cin>>x;
                maxx=max(maxx,x);
                minn=min(minn,x);
            }
            cout<<maxx-minn<<'\n';
        }
        return 0;
    }
    

    B - Make AP

    题意:仅进行一次如下操作:选择\(a,b,c\)中的一个数,让其乘上一个正整数\(m\),最终\(a,b,c\)形成等差数列。

    思路:由于是等差数列,所以最终的\(a,b,c\)满足\(a+c=2\cdot b\)。我们分别讨论改变\(a,b,c\)形成等差数列的可行性。如果改变\(a\),我们需要考虑\((2\cdot b-c)%a\)是否为\(0\),同时商是否大于\(0\);改变\(c\)类似。改变\(b\)需要多考虑\((a+c)\)是否能被\(2\)整除。

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 100010;
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            bool flag=0;
            int a,b,c;
            int ma,mb,mc;
            cin>>a>>b>>c;
            ma=b-(c-b);
            if(ma%a==0 && ma/a>0)
            {
                cout<<"YES\n";
                continue;
            }
            mc=b+(b-a);
            if(mc%c==0 && mc/c>0)
            {
                cout<<"YES\n";
                continue;
            }
            if((c+a)%2==0)
            {
                mb=(a+c)/2;
                if(mb%b==0 && mb/b>0)
                {
                    cout<<"YES\n";
                    continue;
                }
            }
            cout<<"NO\n";
        }
        return 0;
    }
    

    C - Division by Two and Permutation

    题意:给出\(n\)个数,重复如下操作:选择其中一个数\(x\)进行\(\lfloor x/2 \rfloor\)。问\(n\)个数能否构成\(1-n\)的排列。

    思路:例如想要获得数字\(2\),它可以从\(4\)\(5\)经过操作得来。可以发现较小的数字可以从多个较大的数字经过操作得到。因此,我们先将所有的数的范围控制在\(1-n\),统计各个数的个数\(f[i]\),从大到小遍历,如果\(f[i]>1\),那么就可以把多的数字进行操作,状态转移方程为\(f[i/2]+=f[i]-1\),最后判断\(1-n\)范围内所有的\(f[i]\)是否均为\(1\)

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 60;
    int f[maxn];
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            int x;
            int n;
            cin>>n;
            for(int i=1;i<=n;i++)
            {
                f[i]=0;
            }
            for(int i=1;i<=n;i++)
            {
                cin>>x;
                while(x>n) x/=2;
                f[x]++;
            }
            for(int i=n;i>=1;i--)
            {
                if(f[i]>1)
                {
                    f[i/2]+=f[i]-1;
                }
            }
            bool ans=1;
            for(int i=1;i<=n;i++)
            {
                if(f[i]==0)
                {
                    ans=0;
                    break;
                }
            }
            if(ans) cout<<"YES\n";
            else cout<<"NO\n";
        }
        return 0;
    }
    

    D - Palindromes Coloring

    题意:给出一个字符串和\(k\)种颜色,对字符串中的字符涂色(必须\(k\)种颜色全部用到,所有字符不需要都涂上色),使得相同颜色的字符在交换顺序后能够形成回文串,问形成的最小回文串的最大长度。

    思路:若想构成回文串,至多一种字符的个数为奇数,其余均为偶数。首先统计每个字符的个数,如果个数为奇数,就将多出来的那一个统计入\(rest\),使得每种字符的统计个数均为偶数,设这些字符个数总数为\(x\),那么可以构成\(k\)个长度为\(x/k\)的回文串与\(x\%k\)个剩余字符。如果\(x/k\)为奇数,那么必然无法加上新的字符,答案即为\(x/k\);如果\(x/k\)为偶数,我们可以对其中的回文串加上新的字符,那么只需要讨论\(x\%k+rest\)\(k\)的大小关系。如果\(x\%k+rest \geq k\),答案为\(x/k+1\),否则为\(x/k\)

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 100010;
    int n,k;
    string s;
    int d[26]={0};
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            int rest=0;
            int sum=0;
            cin>>n>>k;
            cin>>s;
            for(int i=0;i<26;i++)
            {
                d[i]=0;
            }
            for(int i=0;i<n;i++)
            {
                d[s[i]-97]++;
            }
            for(int i=0;i<26;i++)
            {
                rest+=d[i]%2;
                d[i]=d[i]/2*2;
                sum+=d[i];
            }
            int ans=sum/k;
            int r=sum%k;
            if(ans%2)
            {
                ans=ans;
            }
            else
            {
                if(r+rest>=k)
                {
                    ans++;
                }
            }
            cout<<ans<<'\n';
        }
        return 0;
    }
    

    E - Masha-forgetful

    题意:给出\(n\)个字符串,给出一种组合方式,使得这\(n\)个字符串的若干个子串可以构成指定的字符串。

    思路:因为不需要考虑最少子串,因此我们把所有的字符串拆成长度为\(2\)\(3\)的子串。然后对于给定的字符串,对于当前位置\(i\),判断包含以位置\(i\)结尾的长度\(2\)\(3\)的子串是否在\(n\)个字符串中出现过,若出现过则记录前驱。最后根据前驱输出答案。

    /* Author: cyanine_farewell
     * Time: 2022-01-20 01:16:59
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 1010;
    int n,m;
    map<string,bool> vis;
    map<string,tuple<int,int,int>> pos;
    bool dp[maxn];
    int pr[maxn];
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            pos.clear();
            vis.clear();
            string s;
            string t;
            cin>>n>>m;
            for(int i=0;i<=m;i++)
            {
                dp[i]=0;
                pr[i]=0;
            }
            dp[0]=1;
            for(int i=1;i<=n;i++)
            {
                cin>>s;
                for(int j=0;j<m;j++)
                {
                    t=s[j];
                    for(int k=1;k<=2;k++)
                    {
                        if(k+j>=m) break;
                        t+=s[j+k];
                        if(!vis[t])
                        {
                            vis[t]=1;
                            pos[t]=make_tuple(j,j+k,i);
                        }
                    }
                }
            }
            cin>>s;
            for(int i=0;i<m;i++)
            {
                t=s[i];
                for(int k=1;k<=2;k++)
                {
                    if(i-k<0) break;
                    t=s[i-k]+t;
                    if(vis[t] && dp[i-k])
                    {
                        dp[i+1]=1;
                        pr[i+1]=i-k;
                    }
                    if(dp[i+1]) break;
                }
            }
            if(!dp[m])
            {
                cout<<"-1\n";
                continue;
            }
            vector<tuple<int,int,int>> ans;
            for(int k=m;k>0;)
            {
                int p=pr[k];
                string t=s.substr(p,k-p);
                ans.emplace_back(pos[t]);
                k=p;
            }
            reverse(ans.begin(),ans.end());
            cout<<ans.size()<<'\n';
            for(auto [l,r,i]:ans)
            {
                cout<<l+1<<' '<<r+1<<' '<<i<<'\n';
            }
        }
        return 0;
    }
    

    F - Interacdive Problem

    题意:交互,给出\(n\),猜测\(x(1\leq x < n)\)的值。交互方式为:给出\(c\)\(x=x+c\),返回\(\lfloor \frac{x}{n} \rfloor\)。交互不超过\(10\)次,\(1\leq n \leq 1000\)

    思路:补题的时候感觉题解的思路不太符合自己的常规想法,改了一些小的细节。假定当前余数范围为\([l,r]\),以第一次为例,余数范围为\([1, n-1]\),进行二分余数的操作,取得\(mid\)后给出\(c=n-mid\),如果返回的结果比上一次大,说明余数范围在\([mid,r]\),反之在\([l,mid]\)。同时,由于\(x=x+c\),因此余数范围也发生了变化,需要加上\(c\)并进行取模。可以在对数次数内找到结果,也就是\(10\)次内。

    需要注意的是,这个思路在\(l=0,r=1,mid=(l+r)/2\)时会进入死循环,因此将\(mid=(l+r+1)/2\)即可。

    最终结果为最后一次返回的结果加上\(l\)(或者\(r\),因为此时\(l==r\))。

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 100010;
    int n;
    int main()
    {
        fast;
        cin>>n;
        int l=1,r=n-1;
        int d=0;
        int x;
        int ans;
        while(l<r)
        {
            int mid=(l+r+1)/2;
            cout<<"+ "<<n-mid<<endl;
            cin>>x;
            if(x>d) l=mid;
            else r=mid-1;
            l=(l+n-mid)%n;
            r=(r+n-mid)%n;
            d=x;
        }
        cout<<"! "<<d*n+l<<endl;
        return 0;
    }
    

    G - MinOr Tree

    题意:给出一张图,问对于或运算的最小生成树的值。

    思路:不需要考虑具体留下哪些边。按位从高位进行处理,判断在去掉该位为\(1\)的边后剩余的边能否连通,若能则去掉这些边,不能则保留。连通性利用并查集可以判断。

    /* Author: cyanine_farewell
     * Time: 2022-01-19 19:30:03
    **/
    #include<bits/stdc++.h>
    #define pb push_back
    #define ll long long
    #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    using namespace std;
    const int maxn = 200010;
    struct Edge{
        int u,v,w;
    };
    bool vis[maxn];
    Edge E[maxn];
    int f[maxn];
    int n,m;
    int Find(int x)
    {
        if(f[x]==x) return x;
        return f[x]=Find(f[x]);
    }
    void Union(int x,int y)
    {
        x=Find(x);
        y=Find(y);
        if(x==y) return;
        f[x]=y;
        return;
    }
    bool check(int x)
    {
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            if(vis[i] || E[i].w&(1<<x)) continue;
            int u=E[i].u,v=E[i].v;
            Union(u,v);
            Union(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            if(Find(1)!=Find(i)) return 0;
        }
        return 1;
    }
    int main()
    {
        fast;
        int T;
        cin>>T;
        while(T--)
        {
            cin>>n>>m;
            for(int i=1;i<=m;i++)
            {
                vis[i]=0;
                cin>>E[i].u>>E[i].v>>E[i].w;
            }
            int res=0;
            for(int i=30;i>=0;i--)
            {
                if(check(i))
                {
                    for(int j=1;j<=m;j++)
                    {
                        if(E[j].w&(1<<i)) vis[j]=1;
                    }
                }
                else res+=(1<<i);
            }
            cout<<res<<'\n';
        }
        return 0;
    }
    
  • 相关阅读:
    CSP-S2019 退役记
    近期考试反思
    有关近期情况的总结与反思
    我好难啊
    AFO
    智障错误集锦
    关于博客密码【asd
    关于csp-s的各种问题整理
    CSP-S 临别赠言( 二 )
    分层图最短路 乱搞分享
  • 原文地址:https://www.cnblogs.com/endlesskkk/p/15830090.html
Copyright © 2020-2023  润新知