日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【NOIP 2017】列队

發布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【NOIP 2017】列队 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

Sylvia 是一個熱愛學習的女♂孩子。
前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。
Sylvia 所在的方陣中有n×m名學生,方陣的行數為 n,列數為 m。
為了便于管理,教官在訓練開始時,按照從前到后,從左到右的順序給方陣中 的學生從 1 到 n×m 編上了號碼(參見后面的樣例)。即:初始時,第 iii 行第 jjj 列 的學生的編號是(i?1)×m+j。
然而在練習方陣的時候,經常會有學生因為各種各樣的事情需要離隊。在一天 中,一共發生了 q 件這樣的離隊事件。每一次離隊事件可以用數對(x,y)(1≤x≤n,1≤y≤m)描述,表示第 x 行第 y 列的學生離隊。
在有學生離隊后,隊伍中出現了一個空位。為了隊伍的整齊,教官會依次下達 這樣的兩條指令:

  • 向左看齊。這時第一列保持不動,所有學生向左填補空缺。不難發現在這條 指令之后,空位在第 x 行第 m 列。
  • 向前看齊。這時第一行保持不動,所有學生向前填補空缺。不難發現在這條 指令之后,空位在第 n 行第 m 列。
    教官規定不能有兩個或更多學生同時離隊。即在前一個離隊的學生歸隊之后, 下一個學生才能離隊。因此在每一個離隊的學生要歸隊時,隊伍中有且僅有第 n 行 第 m 列一個空位,這時這個學生會自然地填補到這個位置。
    因為站方陣真的很無聊,所以 Sylvia 想要計算每一次離隊事件中,離隊的同學 的編號是多少。
    注意:每一個同學的編號不會隨著離隊事件的發生而改變,在發生離隊事件后 方陣中同學的編號可能是亂序的。
  • solution

    正解:線段樹/樹狀數組/平衡樹
    \(30\%\):開個 \(n*m\) 的數組模擬即可
    \(50\%\):發現只有500行有改動,所以單獨拿出這500行和最后一列,模擬即可.
    \(80\%\):只有一行的話,我們就開一個 \(m+q\) 的數組,然后樹狀數組維護每一個位置是否有人,并且維護每一個位置的人的id,這樣就會產生很多空位,詢問就是查找第 \(y\) 個有人的位置的id,二分+樹狀數組 或 直接線段樹查找第k大即可,與 \(70\) 分不同的是,還需要再維護最后一列,像行一樣維護即可
    \(100\%\):和 \(80\) 分類似,想到有很多位置根本沒有大的變動,我們像之前一樣,我們把只需要出隊的位置刪除即可,所以我們維護每一個位置是否被刪,但是不太好存,所以用動態開點線段樹標記刪除位置,然后像之前一樣二分找出第 \(y\) 個有人的位置即可,還有一個不同的是,id數組需要動態維護,所以開個vector存即可,所以100和80的區別僅在于是否使用動態內存.

    前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; }

    轉載于:https://www.cnblogs.com/Yuzao/p/7920813.html

    總結

    以上是生活随笔為你收集整理的【NOIP 2017】列队的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。