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