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 列的學生離隊。
在有學生離隊後,隊伍中出現了一個空位。為了隊伍的整齊,教官會依次下達 這樣的兩條指令:
向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條 指令之後,空位在第 x 行第 m列。
向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條 指令之後,空位在第 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; }