【NOIP2011普及組】瑞士輪

這裏寫圖片描述

題目意思:給你兩個數組w和s,要求每次第一名(a[1])和第二(a[2])、第三和第四、第五和第六、第i(i+1<=n)和i+1名比賽,如果a[i].w>a[i+1].w則a[i].s++,然後重新按照a[i].s排序,重複以上操作直到操作次數等於R爲止。求此時的A[Q].id
不難想到暴力算法,先把a排序,然後順序掃描整個a如果a[i].w>a[i+1].w則a[i].s++,然後再快排一次。
時間複雜度爲O(R*(2*n)*log2(2*n))對於本題n<=100000,R<=50的規模
運算次數爲50*200000*18=1.8億次,會超時。
正解,設一個數組Win存儲這一輪贏了的人,Lose存儲輸的。
依然是順序掃描a,把贏了的人放入Win中,輸了的放入Lose中。
然後把Win和Lose按照cmp來合併,合併後的數組就是新的a,更新a,繼續下一次歸併排序直到次數等於R,輸出答案;
這種做法由於是直接合並,掃描是O(2*n)的,所以最後的時間複雜度是O(R*2*n)就可以過了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define maxn 100005
#define inf 1000000010
using namespace std;
int n,R,Q;
struct data
{
    int id,s,w;
}Win[2*maxn],Lose[2*maxn],Ans[2*maxn];

bool cmp(data a,data b)
{
    return a.s>b.s || (a.s==b.s && a.id<b.id);
}

void solve()
{
    int ai=1,bi=1;
    for(int i=1;i<=2*n;i+=2)
    {
        if(Ans[i].w<Ans[i+1].w)
        {
            Ans[i+1].s++;
            Win[ai++]=Ans[i+1];
            Lose[bi++]=Ans[i]; 
        }
        else
        {   
            Ans[i].s++;
            Win[ai++]=Ans[i];
            Lose[bi++]=Ans[i+1]; 
        }
    }

    int i=1,j=1,k=1;
    while(i<ai && j<bi)
    {
        if(cmp(Win[i],Lose[j]))
        {
            Ans[k++]=Win[i];
            i++;
        }
        else
        {
            Ans[k++]=Lose[j];
            j++;
        }
    }

    while(i<ai)Ans[k++]=Win[i++];
    while(j<bi)Ans[k++]=Lose[j++];
}

int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);

    scanf("%d%d%d",&n,&R,&Q);
    for(int i=1;i<=2*n;i++)
    {
    scanf("%d",&Ans[i].s);
    Ans[i].id=i;
    }
    for(int i=1;i<=2*n;i++)
    scanf("%d",&Ans[i].w);
    sort(Ans+1,Ans+2*n+1,cmp);

    for(int i=1;i<=R;i++)
    solve();

    printf("%d\n",Ans[Q].id);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章