【NOIP 2017】列队
Description
Sylvia 是一個(gè)熱愛學(xué)習(xí)的女♂孩子。
前段時(shí)間,Sylvia 參加了學(xué)校的軍訓(xùn)。眾所周知,軍訓(xùn)的時(shí)候需要站方陣。
Sylvia 所在的方陣中有n×m名學(xué)生,方陣的行數(shù)為 n,列數(shù)為 m。
為了便于管理,教官在訓(xùn)練開始時(shí),按照從前到后,從左到右的順序給方陣中 的學(xué)生從 1 到 n×m 編上了號(hào)碼(參見后面的樣例)。即:初始時(shí),第 iii 行第 jjj 列 的學(xué)生的編號(hào)是(i?1)×m+j。
然而在練習(xí)方陣的時(shí)候,經(jīng)常會(huì)有學(xué)生因?yàn)楦鞣N各樣的事情需要離隊(duì)。在一天 中,一共發(fā)生了 q 件這樣的離隊(duì)事件。每一次離隊(duì)事件可以用數(shù)對(duì)(x,y)(1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的學(xué)生離隊(duì)。
在有學(xué)生離隊(duì)后,隊(duì)伍中出現(xiàn)了一個(gè)空位。為了隊(duì)伍的整齊,教官會(huì)依次下達(dá) 這樣的兩條指令:
教官規(guī)定不能有兩個(gè)或更多學(xué)生同時(shí)離隊(duì)。即在前一個(gè)離隊(duì)的學(xué)生歸隊(duì)之后, 下一個(gè)學(xué)生才能離隊(duì)。因此在每一個(gè)離隊(duì)的學(xué)生要?dú)w隊(duì)時(shí),隊(duì)伍中有且僅有第 n 行 第 m 列一個(gè)空位,這時(shí)這個(gè)學(xué)生會(huì)自然地填補(bǔ)到這個(gè)位置。
因?yàn)檎痉疥囌娴暮軣o(wú)聊,所以 Sylvia 想要計(jì)算每一次離隊(duì)事件中,離隊(duì)的同學(xué) 的編號(hào)是多少。
注意:每一個(gè)同學(xué)的編號(hào)不會(huì)隨著離隊(duì)事件的發(fā)生而改變,在發(fā)生離隊(duì)事件后 方陣中同學(xué)的編號(hào)可能是亂序的。
solution
正解:線段樹/樹狀數(shù)組/平衡樹
\(30\%\):開個(gè) \(n*m\) 的數(shù)組模擬即可
\(50\%\):發(fā)現(xiàn)只有500行有改動(dòng),所以單獨(dú)拿出這500行和最后一列,模擬即可.
\(80\%\):只有一行的話,我們就開一個(gè) \(m+q\) 的數(shù)組,然后樹狀數(shù)組維護(hù)每一個(gè)位置是否有人,并且維護(hù)每一個(gè)位置的人的id,這樣就會(huì)產(chǎn)生很多空位,詢問(wèn)就是查找第 \(y\) 個(gè)有人的位置的id,二分+樹狀數(shù)組 或 直接線段樹查找第k大即可,與 \(70\) 分不同的是,還需要再維護(hù)最后一列,像行一樣維護(hù)即可
\(100\%\):和 \(80\) 分類似,想到有很多位置根本沒有大的變動(dòng),我們像之前一樣,我們把只需要出隊(duì)的位置刪除即可,所以我們維護(hù)每一個(gè)位置是否被刪,但是不太好存,所以用動(dòng)態(tài)開點(diǎn)線段樹標(biāo)記刪除位置,然后像之前一樣二分找出第 \(y\) 個(gè)有人的位置即可,還有一個(gè)不同的是,id數(shù)組需要?jiǎng)討B(tài)維護(hù),所以開個(gè)vector存即可,所以100和80的區(qū)別僅在于是否使用動(dòng)態(tài)內(nèi)存.
前50%和另外 20%
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #define RG register using namespace std; typedef long long ll; const int N=50005,M=300005; int n,m,Q,b[M],num=0,tot; struct node{int x,y;}e[M];namespace brute{ll a[505][N],line[N],r[N];void main(){for(int i=1;i<=tot;i++)for(int j=1;j<=m;j++)a[i][j]=(ll)(b[i]-1)*m+j;for(int i=1;i<=n;i++)line[i]=(ll)(i-1)*m+m;for(int P=1;P<=Q;P++){int x=e[P].x,y=e[P].y,hxy;printf("%lld\n",a[x][y]);hxy=a[x][y];for(int i=y;i<m;i++)r[i]=a[x][i+1];for(int i=y;i<m;i++)a[x][i]=r[i];for(int i=b[x];i<n;i++)r[i]=line[i+1];for(int i=b[x];i<n;i++)line[i]=r[i];line[n]=hxy;for(int i=1;i<=tot;i++)a[i][m]=line[b[i]];}} }namespace cheat{int id[M*2],tr[M*2];void add(int sta,int ad){for(int i=sta;i<=m+Q;i+=(i&(-i)))tr[i]+=ad;}int qry(int sta){int ret=0;for(int i=sta;i>=1;i-=(i&(-i)))ret+=tr[i];return ret;}int midit(int k){int l=1,r=m+Q,mid,tmp,ret=0;while(l<=r){mid=(l+r)>>1;tmp=qry(mid);if(tmp>=k)ret=mid,r=mid-1;else l=mid+1;}return ret;}void main(){for(int i=1;i<=m;i++)add(i,1),id[i]=i;int cnt=m;for(int P=1;P<=Q;P++){int y=e[P].y;int p=midit(y);printf("%d\n",id[p]);cnt++;add(p,-1);add(cnt,1);id[cnt]=id[p];}} }void work(){scanf("%d%d%d",&n,&m,&Q);for(int i=1;i<=Q;i++){scanf("%d%d",&e[i].x,&e[i].y);b[++num]=e[i].x;}sort(b+1,b+num+1);tot=unique(b+1,b+num+1)-b-1;for(int i=1;i<=n;i++)e[i].x=lower_bound(b+1,b+tot+1,e[i].x)-b;if(Q<=500)brute::main();else{if(n==1)cheat::main();else brute::main();} }int main(){work();return 0; }100分
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <vector> #include <cmath> #define RG register #define il inline #define iter iterator #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; const int N=300005,M=6000100; vector<ll>S[N]; int n,m,Q,tot,root[N],ls[M],rs[M],v[M],cnt=0;inline void Modify(int &rt,int l,int r,int sa){if(!rt)rt=++cnt;v[rt]++;if(l==r)return ;int mid=(l+r)>>1;if(sa<=mid)Modify(ls[rt],l,mid,sa);else Modify(rs[rt],mid+1,r,sa); }inline int qry(int rt,int l,int r,int k){if(l==r)return l;int mid=(l+r)>>1;int sum=mid-l+1-v[ls[rt]];if(k<=sum)return qry(ls[rt],l,mid,k);return qry(rs[rt],mid+1,r,k-sum); }inline ll caline(int x){int r=qry(root[n+1],1,tot,x);Modify(root[n+1],1,tot,r);return r<=n?1ll*(r-1)*m+m:S[n+1][r-n-1]; } inline ll calrow(int x,int y){int r=qry(root[x],1,tot,y);Modify(root[x],1,tot,r);return r<m?1ll*(x-1)*m+r:S[x][r-m]; }void work() {int x,y;ll ret,tmp;scanf("%d%d%d",&n,&m,&Q);tot=Max(n,m)+Q;while(Q--){scanf("%d%d",&x,&y);if(y==m){ret=caline(x);S[n+1].push_back(ret);printf("%lld\n",ret);}else{ret=calrow(x,y);printf("%lld\n",ret);S[n+1].push_back(ret);tmp=caline(x);S[x].push_back(tmp);}} }int main() {freopen("pp.in","r",stdin);freopen("pp.out","w",stdout);work();return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/Yuzao/p/7920813.html
總結(jié)
以上是生活随笔為你收集整理的【NOIP 2017】列队的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: yii2 php反射,Yii2.0-ad
- 下一篇: Java 同步器