zoukankan      html  css  js  c++  java
  • Codeforces 1072

    链接:http://codeforces.com/contest/1072/


    A - Golden Plate - [计算题]

    #include<bits/stdc++.h>
    using namespace std;
    inline int calc(int w,int h){return (w+h-2)*2;}
    int w,h,k;
    int ans;
    int main()
    {
        cin>>w>>h>>k;
        for(;w&&h&&k;w-=4,h-=4,k--) ans+=calc(w,h);
        cout<<ans<<endl;
    }

    B - Curiosity Has No Limits - [DFS]

    对于常数 $C_1,C_2$ 和变量 $x,y$ 的方程组:

    $left{ {egin{array}{*{20}c} {C_1 = x|y} \ {C_2 = x& y} \ end{array}} ight.$

    除了 $x$ 和 $y$ 之间能互换一下之外,其实解是唯一的。

    因此,说是从 $1$ 到 $n$ 的深搜,其实只是 $O(n)$ 的枚举,因为当你确定了第一个数字 $t[1]$ 之后,后面的跟着都是确定的,因此只会DFS只会跑一条深度为 $n$ 的链。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pii;
    const int maxn=1e5+50;
    
    int n;
    pii a[maxn],b[maxn];
    pii cho[4];
    bool judge(pii a,pii b,pii x,pii y)
    {
        if((x.first|y.first)!=a.first || (x.second|y.second)!=a.second) return 0;
        if((x.first&y.first)!=b.first || (x.second&y.second)!=b.second) return 0;
        return 1;
    }
    
    bool ok;
    int c[maxn];
    void dfs(int d,int p)
    {
        if(ok) return;
        if(d==n+1)
        {
            ok=1;
            return;
        }
        for(int i=0;i<=3;i++)
        {
            if(judge(a[d-1],b[d-1],cho[p],cho[i]))
            {
                c[d]=i;
                dfs(d+1,i);
            }
        }
    }
    
    int main()
    {
        cho[0]=make_pair(0,0);
        cho[1]=make_pair(0,1);
        cho[2]=make_pair(1,0);
        cho[3]=make_pair(1,1);
        cin>>n;
        for(int i=1,k;i<n;i++)
        {
            scanf("%d",&k);
            a[i].first=k/2;
            a[i].second=k%2;
        }
        for(int i=1,k;i<n;i++)
        {
            scanf("%d",&k);
            b[i].first=k/2;
            b[i].second=k%2;
        }
    
        ok=0;
        for(int i=0;i<=3;i++)
        {
            c[1]=i;
            dfs(2,i);
            if(ok) break;
        }
        if(ok)
        {
            printf("YES
    ");
            for(int i=1;i<=n;i++) printf("%d ",c[i]);
            printf("
    ");
        }
        else printf("NO
    ");
    }

    C - Cram Time - [暴力]

    (忍不住想说,我队友太强了,跟他组队是我拖后腿了55555)

    显然,要放最多的数进去,肯定是放 $1 sim n$,其中 $n$ 是满足 $frac{{left( {n + 1} ight)n}}{2} le a + b$ 的最大整数。

    考虑第一天看 $a$ 的书,我们从最大的 $n$ 枚举起,遇到能塞得下的就往里塞,这样必然可以让第一天的 $a$ 个小时被占满,

    而剩下的全部放到第二天就行了,剩下的那些加起来必然不会超过 $b$ 小时。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=63300;
    
    ll a,b;
    ll n;
    bool vis[maxn];
    
    int main()
    {
        cin>>a>>b;
        for(n=0;n<maxn;n++) if((n+1)*n/2<=a+b && (n+2)*(n+1)/2>a+b) break;
    
        memset(vis,0,sizeof(vis));
        int cnt=0;
        for(int i=n;i>=1;i--)
        {
            if(a>=i)
            {
                vis[i]=1;
                a-=i;
                cnt++;
            }
        }
    
        printf("%d
    ",cnt);
        for(int i=1;i<=n;i++) if(vis[i]) printf("%d ",i);
        printf("
    ");
        printf("%d
    ",n-cnt);
        for(int i=1;i<=n;i++) if(!vis[i]) printf("%d ",i);
        printf("
    ");
    }

    D - Minimum path - [BFS]

    题意:

    给出存储小写字母的 $n imes n$ 的矩阵,规定每次只能往下跑一格或者往右跑一个,要从左上角的 $(1,1)$ 跑到右下角 $(n,n)$,问路径上产生的字符串字典序最小是哪个(另外, 你有 $k$ 次机会能够修改某个字母为任意一个字母)。

    题解:

    按照反对角线,从第 $1$ 层的 $(1,1)$ 跑到第 $2 imes n - 1$ 层的 $(n,n)$,构建两个队列(数组模拟)q[0] 和 q[1],

    队列里面存储一个Node结构体,Node结构体中存储:目前我走到的了 $(i,j)$,给相应路径上产生字符 $c$,接下来我还有多少次 $k$ 能用。

    1、从当前层下一层BFS,从当前 q[f] 队列(其中 f = 0 or 1)取出节点,最多有 $O(n)$ 个节点。

    2、通过这个节点计算出它下一层可能会走到的节点,入队 q[f^1]。

    3、同时,在入队时,我们要把所有能去重的全都去重(就是当前层的两格 $(i+1,j)$ 和 $(i,j+1)$ 都走到下一层的 $(i+1,j+1)$,这种情况只需要判断一下哪个更优即可,显然是字符越小的越优,如果字符相同,那么肯定是 $k$ 越大越优);

    4、另外,我们用 $mini$ 变量记录 q[f^1] 队列中所有元素里字典序最小的字符(这个字符就是要求输出的字符串中第 $k$ 个位置上的字符),而对于 q[f^1] 中大于 $mini$ 的字符的元素,统统都可以去掉(用vis数组标记掉),如果处理完发现 q[f^1] 队列已经空了,就跳出BFS;否则就清空 q[f] 队列,然后令 f^=1,回到步骤 1 继续。

    时间复杂度:

    BFS一共前进 $O(n)$ 层,每层要遍历一遍当前队列取出当前节点,而队列中元素不超过 $O(n)$,同时产生的下个队列内元素一样不会超过 $O(n)$,因此时间复杂度为 $O(n^2)$。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2100;
    
    int n,k;
    char mp[maxn][maxn];
    vector<char> ans;
    
    struct Node{
        char c;
        int i,j;
        int k;
        Node(){}
        Node(char _c,int _i,int _j,int _k){c=_c,i=_i,j=_j,k=_k;}
        bool operator<(const Node& oth)const
        {
            if(c==oth.c) return k>oth.k;
            else return c<oth.c;
        }
    };
    
    int tot[2];
    Node q[2][2*maxn];
    int vis[maxn][maxn];
    const int dx[2]={0,1},dy[2]={1,0};
    inline bool in(int i,int j){return (1<=i && i<=n && 1<=j && j<=n);}
    void bfs()
    {
        tot[0]=0;
        tot[1]=0;
        memset(vis,-1,sizeof(vis));
    
        if(mp[1][1]=='a') q[0][tot[0]++]=Node('a',1,1,k);
        else q[0][tot[0]++]=Node(k?'a':mp[1][1],1,1,max(0,k-1));
        ans.push_back(q[0][0].c);
        vis[1][1]=0;
    
        int f=0;
        Node now,nxt;
        while(tot[f])
        {
            int mini=(int)('z'+10);
            for(int i=0;i<tot[f];i++)
            {
                now=q[f][i];
                if(vis[now.i][now.j]==-1) continue;
                for(int z=0;z<=1;z++)
                {
                    int x=now.i+dx[z], y=now.j+dy[z];
                    if(!in(x,y)) continue;
    
                    if(mp[x][y]=='a') nxt=Node('a',x,y,now.k);
                    else nxt=Node(now.k?'a':mp[x][y],x,y,max(0,now.k-1));
                    if(vis[x][y]==-1)
                    {
                        vis[x][y]=tot[f^1];
                        q[f^1][tot[f^1]++]=nxt;
                        mini=min(mini,(int)nxt.c);
                    }
                    else
                    {
                        Node &tmp=q[f^1][(vis[x][y])];
                        if(nxt<tmp) tmp=nxt, mini=min(mini,(int)nxt.c);
                    }
                }
            }
    
            if(mini<(int)('z'+10)) ans.push_back((char)mini);
            else break;
    
            for(int i=0;i<tot[f^1];i++)
            {
                nxt=q[f^1][i];
                if((int)nxt.c>mini) vis[nxt.i][nxt.j]=-1;
            }
    
            tot[f]=0;
            f^=1;
        }
    }
    
    int main()
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    
        if(k+1>=n+n)
        {
            for(int i=1;i<=2*n-1;i++) printf("a");
            printf("
    ");
            return 0;
        }
    
        ans.clear();
        bfs();
        for(int i=0;i<ans.size();i++) printf("%c",ans[i]);
        printf("
    ");
    }
  • 相关阅读:
    Mutex 的正确打开方式
    常用 CMD 命令
    【LeetCode】在排序数组中查找元素的第一个和最后一个位置【三次二分】
    【LeetCode】搜索旋转排序数组【两次二分】
    【手写代码】计算1-n中总共有多少二进制1
    【手写代码】快速计算数字x有多少个二进制1
    【手写代码】建立二叉搜索树
    【LeetCode】下一个排列【找规律】
    【LeetCode】删除排序数组中的重复项&&移除特定元素【双指针,原地算法】
    【LeetCode】删除链表的倒数第N个节点【双指针法】
  • 原文地址:https://www.cnblogs.com/dilthey/p/9826351.html
Copyright © 2011-2022 走看看