• Codeforces Round #552 (Div. 3)-1154E-Two Teams-(模拟+双指针)


    http://codeforces.com/contest/1154/problem/E

    解题:

    举例n=10,k=1

    1,2,10,4,7,6,9,8,5,3

    第一次,1队先挑2,10,4这三个人

    1,2,10,4,7,6,9,8,5,3

    第二次,2队挑6,9,8三个人

    1,2,10,4,7,6,9,8,5,3

    第三次,1队挑1,7,5三个人

    1,2,10,4,7,6,9,8,5,3

    第四次,2队挑3一个人

    1,2,10,4,7,6,9,8,5,3

    显然需要实现的有两点

    (1)挑完后的“连接”,比如

    第一次挑完后需要把1和7“连接”起来

    第二次挑完后需要把7和5“连接”起来

    用l数组标记当前下标 左边相邻的数的下标

    用r数组标记当前下标 右边相邻的数的下标

    例如一开始:

    r[1]=2,表示下标为1的人(1)的右边是下标为2那个人(2)

    l[5]=4,表示下标为5的人(7)的左边是下标为3那个人(4)

    第一次挑完之后

    r[1]=5,表示下标为1的人(1)的右边是下标为5那个人(7)

    l[5]=1,表示下标为5的人(7)的左边是下标为1那个人(1)

    每次挑完人后把已经挑选的人“删掉”,左右扩散找人可以通过左右数组来找人,直接跳过被挑选过的人,实现“删掉”,

    (2)快速找最大值,暴力寻找肯定会超时

    一般遇到n个不同的数随机出现在数组里,可以用下标数组idx标记这个数出现的下标位置,直接查找。

    dix[10]=3表示10这个数在原数组的下标位置是3

    这里可以从n开始减小,一直减到1,时间复杂度O(n)

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<algorithm>
    #include<string>
    #include<vector>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    
    int n,k,maxxidx,maxx;
    int a[200005];
    int l[200005];///下标为i的人 的左边 下标是多少
    int r[200005];///下标为i的人 的右边 下标是多少
    int idx[200005];///标记原数组下标
    int ans[200005];
    
    void findmax()///找最大值,主要是改变全局变量maxxidx和maxx
    {
        while(maxx>=1)
        {
            if( ans[ idx[maxx] ]==0 )
            {
                maxxidx=idx[ maxx ];
                break;
            }
            maxx--;
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            memset(a,0,sizeof(a));
            memset(l,0,sizeof(l));
            memset(r,0,sizeof(r));
            memset(idx,0,sizeof(idx));
            memset(ans,0,sizeof(ans));
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                idx[ a[i] ]=i;
                l[i]=i-1;
                r[i]=i+1;
            }
            l[n+1]=n;
            r[0]=1;
            maxxidx=idx[n];///初始化为最大的下标
            maxx=n;
            int now=0;///当前已经选了多少人
            int t=1;///初始是1队先挑人
            while(now<n)
            {
                findmax();
                int i=maxxidx;///最大的那个人的下标
                ans[i]=t;
                now++;
                int x=l[i];
                int y=r[i];///中间向左右两边扩展
                for(int j=1;j<=k;j++)
                {
                    if(x>=1 && x<=n)///如果x是0表明左边无人了
                        ans[x]=t,x=l[x],now++;///通过左右指针数组找下一个人
                    if(y>=1 && y<=n)
                        ans[y]=t,y=r[y],now++;
                }
                ///挑完人就该改左右下标了
                l[y]=x;
                r[x]=y;
                if(t==1)
                    t=2;
                else
                    t=1;
            }
            for(int i=1;i<=n;i++)
                printf("%d",ans[i]);
            printf("
    ");
        }
        return 0;
    }

     

  • 相关阅读:
    UVA 10608 Friends
    UVA 10806 Dijkstra, Dijkstra.
    HDU 3715 Go Deeper
    poj1315
    poj1383
    poj1650
    poj1265
    poj1523
    RedHat9.0虚拟机安装
    注册DirectShow filter时应该注意中文路径
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/10840491.html