1. 程式人生 > >P3960 [NOIP2017]列隊-50分暴力

P3960 [NOIP2017]列隊-50分暴力

Sylvia 是一個熱愛學習的女孩子。

前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。

Sylvia 所在的方陣中有n×m名學生,方陣的行數為 n,列數為 m。

為了便於管理,教官在訓練開始時,按照從前到後,從左到右的順序給方陣中 的學生從 1 到 n×m 編上了號碼(參見後面的樣例)。即:初始時,第 ii 行第 jj 列 的學生的編號是(i−1)×m+j。

然而在練習方陣的時候,經常會有學生因為各種各樣的事情需要離隊。在一天 中,一共發生了 qq件這樣的離隊事件。每一次離隊事件可以用數對(x,y) (1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的學生離隊。

在有學生離隊後,隊伍中出現了一個空位。為了隊伍的整齊,教官會依次下達 這樣的兩條指令:

  1. 向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條 指令之後,空位在第 x 行第 m列。

  2. 向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條 指令之後,空位在第 n 行第 m列。

教官規定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之後, 下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第 n 行 第 m 列一個空位,這時這個學生會自然地填補到這個位置。

因為站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學 的編號是多少。

注意:每一個同學的編號不會隨著離隊事件的發生而改變,在發生離隊事件後 方陣中同學的編號可能是亂序的。

這是一篇50分暴力題解!!!想要AC的大佬請跳過~~~

相信大部分人在考場上是不會考慮Splay的......畢竟這也不是noip考點!

但是這道題的暴力分足足有50分!!拿到這50分也是很值得的!

因為50%的時候,q是小於等於500的,但是很重要的一點,每一次出隊只會影響所在的行和最後一列,也就是說最壞的情況只需要維護500行和最後一列即可!!!

STL:unique是把陣列去重後,返回新的陣列長度!具體自行百度。

以下具體看50分程式碼吧~~~

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
inline int r()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node
{
    int x,y;
}e[300001];
int n,m,q,tot;
ll last[300001],h[300001],pos[501][50001];
ll ans;
int main()
{
    n=r();m=r();q=r();
    for(int i=1;i<=q;i++){
        e[i].x=r();
        e[i].y=r();
        h[i]=e[i].x;//h陣列存的是每一次出隊人的橫座標
    }
    for(int i=1;i<=n;i++){
        last[i]=last[i-1]+m;//last維護最後一列的編號!
    }
    sort(h+1,h+q+1);//去重之前要排序
    tot=unique(h+1,h+q+1)-h-1;//去重之後原陣列只剩下tot大小,也就是說我們只需要維護tot行即可
    ll t;
    for(int i=1;i<=tot;i++){
        t=(ll)(h[i]-1)*m;
        for(int j=1;j<=m;j++){
            pos[i][j]=++t;//給每一行每一列都標上號
        }
    }
    int nx;
    for(int i=1;i<=q;i++){
        for(int j=1;j<=tot;j++){
            if(h[j]==e[i].x){//尋找e[i].x在h陣列中的位置,也就是其在去重後的行數
                nx=j;
                break;
            }
        }
        if(e[i].y==m){//如果出隊的這個人在最後一列
            ans=last[h[nx]];
        }
        else{
            ans=pos[nx][e[i].y];
        }
        printf("%lld\n",ans);
        if(e[i].y!=m){//向左看齊
            for(int j=e[i].y;j<m-1;j++){
                pos[nx][j]=pos[nx][j+1];
            }
            pos[nx][m-1]=last[h[nx]];
        }
        for(int j=h[nx];j<n;++j){向前看齊
            last[j]=last[j+1];
        }
        last[n]=ans;
    }
    return 0;
}