1. 程式人生 > >NOIP2016 提高組 第二天第二題 蚯蚓earthworm 題解

NOIP2016 提高組 第二天第二題 蚯蚓earthworm 題解

題目描述

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

蛐蛐國最近蚯蚓成災了!隔壁跳蚤國的跳蚤也拿蚯蚓們沒辦法,蛐蛐國王只好去請神刀手來幫他們消滅蚯蚓。

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

每一秒,神刀手會在所有的蚯蚓中,準確地找到最長的那一隻(如有多個則任選一個)將其切成兩半。神刀手切開蚯蚓的位置由常數p(是滿足0

輸入輸出格式

輸入格式:
第一行包含六個整數n,m,q,u,v,t,其中:n,m,q的意義見【問題描述】;u,v,t均為正整數;你需要自己計算p

=u/v(0<u<v)t是輸出引數,其含義將會在【輸出格式】中解釋。

第二行包含n個非負整數,為ai,a2,…,an,即初始時n只蚯蚓的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。

1<=n<=1050<m<71060<u<v<1090<=q<=2001<t<710<ai<108

輸出格式:
第一行輸出[m/t]個整數,按時間順序,依次輸出第t秒,第2t秒,第3t秒……被切斷蚯蚓(在被切斷前)的長度。

第二行輸出[(n+m)/t]個整數,輸出m秒後蚯蚓的長度;需要按從大到小的順序,依次輸出排名第t,第2t,第3t……的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。即使某一行沒有任何數需要 輸出,你也應輸出一個空行。

請閱讀樣例來更好地理解這個格式。

輸入輸出樣例

輸入樣例#1:
3 7 1 1 3 1
3 3 2
輸出樣例#1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
輸入樣例#2:
3 7 1 1 3 2
3 3 2
輸出樣例#2:
4 4 5
6 5 4 3 2
輸入樣例#3:
3 7 1 1 3 9
3 3 2
輸出樣例#3:
//空行
2

題解

發現性質:
1.先切的蚯蚓一定比後切的蚯蚓原來(初始)長度長
2.長的蚯蚓分成的兩段一定比短的蚯蚓分成的兩段要長

先考慮蚯蚓不會長大的情況
先建三個佇列
可以先將所有蚯蚓按照從大到小的順序,存到第一個佇列裡。
每次取三個佇列的最大值,切成兩段,(此時答案一定是最優的,根據性質1),分別加入第二個和第三個佇列
注意:除了初始的蚯蚓,不會有東西加入到第一個佇列裡
可以保證每個佇列都是單調遞減的(根據性質2),這樣同時也保證了上面“每次取三個佇列的最大值”時的答案一定是最優的
會長大的情況呢?
將整體的長大變成個體的縮短

具體來說
用一個變數存當前的操作次數*每次增加長度,設為l
在每一條蚯蚓存進佇列之前,佇列中的長度為l
那麼對於每一條蚯蚓,實際長度為+l
這樣就可以不用一條一條的增加蚯蚓長度了

程式碼

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 8010000
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,t,h[N],r[N];
int q,a[N],d[3][N];
ll u,v;
bool cnt(int x,int y){return x>y;}
int main()
{
    freopen("earthworm.in","r",stdin);
    freopen("earthworm.out","w",stdout);
    scanf("%d%d%d%lld%lld%d",&n,&m,&q,&u,&v,&t);
    memset(d,128,sizeof(d));
    fo(i,1,n) scanf("%d",&a[i]);
    sort(a+1,a+n+1,cnt);
    fo(i,1,n) d[0][i]=a[i];h[0]=1;r[0]=n;
    h[1]=h[2]=1;r[1]=r[2]=0;
    int l=0;
    fo(o,1,m)
    {
        int mx=-123456789,mi;
        fo(i,0,2) if(d[i][h[i]]>mx&&h[i]<=r[i]) mx=d[i][h[i]],mi=i;
        mx+=l;
        int x=(int)((ll)mx*u/v);
        int y=(mx-x);
        if(o%t==0) printf("%d ",mx);
        h[mi]++;l+=q;
        d[1][++r[1]]=x-l;d[2][++r[2]]=y-l;
    }
    printf("\n");
    fo(o,1,n+m)
    {
        int mx=-2147483647,mi=-1;
        fo(i,0,2) if(d[i][h[i]]>mx&&h[i]<=r[i]) mx=d[i][h[i]],mi=i;
        h[mi]++;
        if(o%t==0) printf("%d ",mx+l);
    }
    fclose(stdin);fclose(stdout);
    return 0;
}