• Codeforces Round #605 (Div. 3)


    A. Three Friends

    题目链接

    题目大意

    给你三个数(a,b,c),每个数可以选择向左,向右或者原地不动,求(min left(left|a-b ight|+left|a-c ight|+left|b-c ight| ight)的值)

    解题思路

    1. 先按定义求出答案,如果三个数都想等的话,就直接输出0,如果有两个数连续的话就减去(2),否则减去(4)
    2. 依然先按定义求出答案,如果小于4,输出0,否则减去4输出。

    AC代码1

    #include <bits/stdc++.h>
    const int maxn = 1e5+100;
    typedef long long ll;
    using namespace std;
    int q;
    ll a[4];
    int main()
    {
        // freopen("data.txt","r",stdin);
        cin>>q;
        while(q--)
        {
            for(int i=0;i<3;i++)
            {
                cin>>a[i];
            }
            sort(a,a+3);
            ll res = a[1]-a[0]+a[2]-a[0]+a[2]-a[1];
            if(a[0]==a[1]&&a[1]==a[2]){
     
            }
            if(a[0]==a[1]&&a[1]+1==a[2]){
                res-=2;
            }else if(a[1]==a[2]&&a[0]+1==a[1]){
                res-=2;
            }else{
                res-=4;
            }
            res = max(1LL*0,res);
            cout<<res<<endl;
        }
    }
    

    AC代码2

    #include <bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    int main()
    {
        int q;
        cin>>q;
        while(q--){
            int a,b,c;
            cin>>a>>b>>c;
            int res = abs(a-b)+abs(b-c)+abs(a-c);
            res = (res>4)?res-4:0;
            cout<<res<<endl;
        }
    }
    

    B. Snow Walking Robot

    题目链接

    题目大意

    在一个方格中,从(0,0)点开始出发,每次可以向上,向下,向右,向左前进一个格子,分别用(U,D,R,L)字符表示,给你一个只包含(U,D,R,L)的字符串,删除尽可能少的字符并且重新排序,同时每个点最多经过一次,使得最后回到(0,0)这个点,输出最后的字符串。

    解题思路

    分别统计(U,D,R,L)的个数,要使得最后回到(0,0)这个点,那么(U)(D)字符的个数必须一样,(R)(L)字符的个数必须一样,则取两者的最大值,再分别输出即可,这里要求一个点最多经过一次,只要(U,D,R,L)中任意一个字符的个数为(0),字符的长度最多为(2)

    AC代码

    #include <bits/stdc++.h>
    const int maxn = 1e5+100;
    typedef long long ll;
    using namespace std;
    int main()
    {
        // freopen("data.txt","r",stdin);
        int q;
        cin>>q;
        while(q--){
            string s;
            cin>>s;
            int a=0,b=0,c=0,d=0;
            for(int i=0;i<s.size();i++){
                if(s[i]=='U'){
                    a++;
                }else if(s[i]=='D'){
                    b++;
                }else if(s[i]=='R'){
                    c++;
                }else{
                    d++;
                }
            }
            int res = min(a,b);
            int res2 = min(c,d);
            if(res==0||res2==0){
                res2=min(res2,1);
                res = min(res,1);
            }
            cout<<(res+res2)*2<<endl;
            for(int i=0;i<res;i++){
                cout<<'U';
            }
            for(int i=0;i<res2;i++){
                cout<<'R';
            }
            for(int i=0;i<res;i++){
                cout<<'D';
            }
            for(int i=0;i<res2;i++){
                cout<<'L';
            }
            cout<<endl;
        }
    }
    

    C. Yet Another Broken Keyboard

    题目链接

    题目大意

    给你一个字符串(s),同时给你(k)个字符的字符数组(t),求(s)中只包含(t)中字符的字串个数。

    解题思路

    首先先遍历字符数组(t),用另外一个数组(str)标记每个字符是否可用,遍历整个字符串,求出每个符合要求的最长字串长度(len),然后答案加上(frac{n imesleft(n+1 ight)}{2})即可。

    AC代码

    #include <bits/stdc++.h>
    const int maxn = 1e5+100;
    typedef long long ll;
    using namespace std;
    bool str[200];
    int main()
    {
        // freopen("data.txt","r",stdin);
        for(int i=0;i<200;i++){
            str[i]=true;
        }
        int n,k;
        cin>>n>>k;
        string s;
        cin>>s;
        getchar();
        for(int i=0;i<k;i++){
            char c;
            cin>>c;
            str[c-'0']=false;
        }
        ll res=0;
        int cnt=0;
        for(int i=0;i<s.size();i++){
            if(str[s[i]-'0']==false){
                cnt++;
            }else{
                res+=1LL*cnt*(1LL*cnt+1)/2;
                cnt=0;
            }
        }
        res+=1LL*cnt*(1LL*cnt+1)/2;
        cout<<res<<endl;
    }
    

    D. Remove One Element

    题目链接

    题目大意

    给你一个包含(n)个数字的数组(a),可以删除数组(a)中最多一个数组,求最长严格递增子数组的长度。

    解题思路

    这道题是个典型的动态规划的题目。

    数组dp[i]表示以(a_i)为起点的最长子数组长度,转移方程为:

    [dp[i]=egin{cases} 1 & i=n \ 1 & a[i]geq a[i+1] \ dp[i+1]+1 & a[i]<a[i+1] \ end{cases} ]

    数组dp2[i]表示以(a_i)为终点的最长子数组长度,转移方程为:

    [dp2[i]=egin{cases} 1 & i=1 \ 1 & a[i-1]geq a[i] \ dp[i-1]+1 & a[i-1]<a[i] \ end{cases} ]

    遍历整个数组(a),如果(a_{i+1}> a_{i-1}),那么结果为(max(result,dp2[i+1]+dp[i-1]))

    AC代码

    #include <bits/stdc++.h>
    const int maxn = 2e5+100;
    typedef long long ll;
    using namespace std;
    int number[maxn];
    ll dp[maxn];
    ll dp2[maxn];
    int main()
    {
        // freopen("data.txt","r",stdin);
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>number[i];
        }
        dp[n]=1;
        ll res=1;
        for(int i=n-1;i>=1;i--){
            if(number[i]<number[i+1]){
                dp[i] = dp[i+1]+1;
                res = max(res,dp[i]);
            }else{
                dp[i]=1;
            }
        }
        dp2[0]=0;
        for(int i=1;i<=n;i++){
            if(number[i]>number[i-1]){
                dp2[i] = dp2[i-1]+1;
            }else{
                dp2[i]=1;
            }
        }
        for(int i=1;i<=n;i++){
            if(i+1<=n&&number[i+1]>number[i-1]){
                res=max(res,dp[i+1]+dp2[i-1]);
            }
        }
        cout<<res<<endl;
    }
    

    E. Nearest Opposite Parity

    题目大意

    给你一个由(n)个整数组成的数组。 一键移动,您可以从位置(i)跳到位置(i-a_i)(如果(1leq (i-a_i)))或跳到位置(i+a_i)(如果(i+a_i leq n))。

    对于从(1)(n)的每个位置(i),您想知道到达任何位置(j)所需的最小移动次数,以使(a_j)(a_i)具有相反的奇偶性(即,如果(a_i)为奇数,则(a_j)必须为偶数,反之亦然)。

    解题思路

    • 思路一:反向建立图,对于偶数的情况,偶数(a_i)到奇数(a_j)的最小移动次数反向建图之后就是所有奇数(a_j)(a_i)的最短路径的长度即位答案,但偶数有那么多个,每个偶数都去计算所有奇数到它的最短路径,时间复杂度太高,这个时候就可以使用超级源点,设一个点到所有奇数的距离为(0),跑一个最短路径出来,所有偶数的答案都出来了。对于奇数的情况也是一样的。即找到两个超级源点跑两次最短路径。
    • 思路二:同样是反向建图,但可以不用最短路径,在建图的过程中找到跳转一次就可以到达的点放入队列中,然后BFS搜索即可。这样的代码量可以减少很多。

    AC代码

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f3f3f3f
    const int maxn=2e5+10;
    typedef long long ll;
    using namespace std;
    typedef pair<long long,int> P;
    struct edge
    {
        int to,cost;
    };
    vector<edge>G[maxn];
    int number[maxn];
    ll d[maxn];
    int n;
    ll res[maxn];
    void dijks(int s)
    {
        priority_queue<P,vector<P>,greater<P> >pq;
        fill(d,d+n+1,INF);
        d[s]=0;
        pq.push(P(0,s));
        while(!pq.empty())
        {
            P p=pq.top();
            pq.pop();
            int v=p.second;
            if(d[v]<p.first)
                continue;
            else
            {
                for(int i=0;i<G[v].size();i++)
                {
                    if(d[G[v][i].to]>d[v]+G[v][i].cost)
                    {
                        d[G[v][i].to]=d[v]+G[v][i].cost;
                        pq.push(P(d[G[v][i].to],G[v][i].to));
                    }
                }
            }
        }
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>number[i];
        }
        for(int i=1;i<=n;i++){
            if(number[i]+i<=n){
                edge e = {i,1};
                G[number[i]+i].push_back(e);
            }
            if(i-number[i]>=1){
                edge e = {i,1};
                G[i-number[i]].push_back(e);
            }
        }
        for(int i=1;i<=n;i++){
            if(number[i]%2==1){
                edge e = {i,0};
                G[0].push_back(e);
            }
        }
        dijks(0);
        for(int i=1;i<=n;i++){
            if(number[i]%2==0){
                res[i] = d[i];
            }
        }
        G[0].clear();
        for(int i=1;i<=n;i++){
            if(number[i]%2==0){
                edge e = {i,0};
                G[0].push_back(e);
            }
        }
        dijks(0);
        for(int i=1;i<=n;i++){
            if(number[i]%2==1){
                res[i] = d[i];
            }
        }
        for(int i=1;i<=n;i++){
            if(res[i]>=INF){
                cout<<"-1"<<" ";
            }else{
                cout<<res[i]<<" ";
            }
        }
        cout<<endl;
    }
    

    F. Two Bracket Sequences

    题目大意

    给你两个括号字符串(s,t),找到一个最短合法字符串满足其子序列包括字符串(s,t)

    解题思路

    这道题也是一道动态规划的题,不过这道题是三维的动态规划。(dp[i][j][k])表示(s)串匹配到(i)(t)串匹配到(j)的时候有(k)(()没有匹配的最小长度。转移方程不是很好写,具体看代码。因为要求子序列包含(s)(t)并且最后的字符串尽可能的短,那么就应该用字符串(s)(t)尽可能的构造合法的括号

    AC代码

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    const int maxn = 2e2+40;
    typedef long long ll;
    using namespace std;
    int n,m;
    string s,t;
    bool res[maxn][maxn][2*maxn];
    int dp[maxn][maxn][2*maxn];
    int dfs(int i,int j,int cnt){
        if(i==n&&j==m)
            return cnt;
        if(cnt>n+m){
            return 1e9;
        }
        if(~dp[i][j][cnt]){
            return dp[i][j][cnt];
        }
        int op1 = 1 + dfs(i+(i<n && s[i]=='('),j + (j<m && t[j]=='(') ,cnt+1),op2 = 1e9;;
        if(cnt){
            op2 = 1 + dfs(i+(i<n && s[i]==')'),j + (j<m && t[j]==')') ,cnt-1);
        }
        res[i][j][cnt]=op1<op2;
        return dp[i][j][cnt]=min(op1,op2);
    }
    int main()
    {
        ios::sync_with_stdio(false);
        memset(dp,-1,sizeof(dp));
        cin>>s>>t;
        n = s.size();
        m = t.size();
        dfs(0,0,0);
        int i=0,j=0,cnt=0;
        while(i<s.size()||j<t.size()){
            if(res[i][j][cnt]){
                i+=(i<n && s[i]=='(');
                j+=(j<m && t[j]=='(');
                cnt++;
                cout<<"(";
            }else{
                i+=(i<n && s[i]==')');
                j+=(j<m && t[j]==')');
                cnt--;
                cout<<")";
            }
        }
        while(cnt--){
            cout<<")";
        }
        cout<<endl;
    }
    

    总结

    终于有一次能把(CodeForces)上的题完整的补完一次了。(A)题真的傻了,那么简单的,当时居然卡了好一会儿。(B)(C,D)题比较简单,只是(D)有个小细节没有处理好,(wa)了两次。(E)(F)是赛后交流之后补的。终于涨分了,呜呜呜

  • 相关阅读:
    ssh 使用密钥文件
    VS2015企业版,社区版,专业版详细对比
    Redis 与 数据库处理数据的两种模式(转)
    工业级物联网项目架构设计思想(转)
    C# and Redis,安装作为服务
    C# CRC32
    c++,C# 转换
    app配置智能硬件的解决方案
    C# 与C++的数据转换
    C++ 对数组sizeof 和对数组元素sizeof
  • 原文地址:https://www.cnblogs.com/zrcsy/p/12188662.html
Copyright © 2020-2023  润新知