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("\n");
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/shoulinniao/p/10840491.html