1. 程式人生 > >UOJ264 NOIP2016 day2 T2 蚯蚓(佇列)

UOJ264 NOIP2016 day2 T2 蚯蚓(佇列)

UOJ264 NOIP2016 day2 T2 蚯蚓

題意:
本題中,我們將用符號 ⌊c⌋ 表示對 c 向下取整,例如:⌊3.0⌋=⌊3.1⌋=⌊3.9⌋=3。

蛐蛐國裡現在共有 n 只蚯蚓(n 為正整數)。每隻蚯蚓擁有長度,我們設第 i 只蚯蚓的長度為 ai (i=1,2,…,n),並保證所有的長度都是非負整數(即:可能存在長度為 0 的蚯蚓)。

每一秒,神刀手會在所有的蚯蚓中找到最長的那一隻(如有多個則任選一個)將其切成兩半。神刀手切開蚯蚓的位置由常數 p(是滿足 0< p<1 的有理數)決定,設這隻蚯蚓長度為 x,神刀手會將其切成兩隻長度分別為 ⌊px⌋ 和 x−⌊px⌋ 的蚯蚓。特殊地,如果這兩個數的其中一個等於 0,則這個長度為 0 的蚯蚓也會被保留。此外,除了剛剛產生的兩隻新蚯蚓,其餘蚯蚓的長度都會增加 q(是一個非負整常數)。

蛐蛐國王決定求助於一位有著洪荒之力的神祕人物,但是救兵還需要 m 秒才能到來……(m 為非負整數)。

蛐蛐國王希望知道這 m 秒內的戰況。具體來說,他希望知道:

m 秒內,每一秒被切斷的蚯蚓被切斷前的長度(有 m 個數);
m 秒後,所有蚯蚓的長度(有 n+m 個數)。
資料範圍
保證 1≤n≤1e5,0≤m≤7×1e6
0< u < v≤1e9,0≤q≤200,1≤t≤71,0≤ai≤1e8。
題解:
雖說暴力又好想又好寫,但是正解真的很妙。
假設有x,y兩隻蚯蚓,滿足len x>=len y,x被切的兩部分分別為a1,b1,y被切的兩部分分別為a2,b2。那麼有一個性質 a1>=a2 ,b1>=b2。
想一下,a1+b1=(原)x,a2+b1=(原)y。
時間對他們的作用是相同的,又因為均是成比例切開,因此仍然滿足原來的大小關係。
因此,我們可以不必維護堆,因為其本身就有單調性。
維護三個佇列 Q0,Q1,Q2。Q1存放原來的大小順序,Q2存放切出的所有a部分,Q2存放切出的所有b部分。每次只需取三個隊隊首最大的那個,再把切出來的兩個部分放入對應隊隊尾即可。
注意維護時間戳(儲存距離上一次被切過了多少秒)來算現在的長度。

程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=100010;
const int M=7000010;
int n,m,q,u,v,t;
struct node
{
    int len,cnt;
    node(int len,int cnt): len(len),cnt(cnt){}
};
queue<node> Q[3
]; int ll[N]; void solve() { int kk=0; for(int inc=1;inc<=m;inc++) { int opt=-1; int mx=-1; for(int i=0;i<3;i++) { if(!Q[i].empty()&&(Q[i].front().len+(inc-1-Q[i].front().cnt)*q>mx)) {mx=Q[i].front().len+(inc-1-Q[i].front().cnt)*q; opt=i;} } node tmp= Q[opt].front(); Q[opt].pop(); int len=tmp.len+(inc-1-tmp.cnt)*q; kk++; if(kk%t==0) { printf("%d",len); if(kk!=(m/t)*t) printf(" "); } int s1=(1LL*len*u)/v; int s2=len-s1; Q[1].push(node(s1,inc)); Q[2].push(node(s2,inc)); } printf("\n"); } void print() { int kk=0; while(1) { if(Q[0].empty()&&Q[1].empty()&&Q[2].empty()) break; int opt=-1; int mx=-1; for(int i=0;i<3;i++) { if(!Q[i].empty()&&(Q[i].front().len+(m-Q[i].front().cnt)*q>mx)) {mx=Q[i].front().len+(m-Q[i].front().cnt)*q; opt=i;} } node tmp= Q[opt].front(); Q[opt].pop(); int len=tmp.len+(m-tmp.cnt)*q; kk++; if(kk%t==0) { printf("%d",len); if(kk!=((m+n)/t)*t) printf(" "); } } printf("\n"); } int main() { scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); for(int i=1;i<=n;i++) scanf("%d",&ll[i]); sort(ll+1,ll+n+1); for(int i=n;i>=1;i--) Q[0].push(node(ll[i],0)); solve(); print(); return 0; }