1. 程式人生 > >[BZOJ3613][Heoi2014]南園滿地堆輕絮 二分答案

[BZOJ3613][Heoi2014]南園滿地堆輕絮 二分答案

out 遞推 fine 最大 愛好者 pre zoj ace amp

Description

小 Z 是 ZRP(Zombies’ Republic of Poetry,僵屍詩歌共和國)的一名詩歌愛好者,最近 他研究起了詩詞音律的問題。 在過去,詩詞是需要編成曲子唱出來的,比如下面這首《菩薩蠻》,唱出來的話其對應 的音符就是這樣的: 南 園 滿 地 堆 輕 絮, 愁 聞 一 霎 清 明 雨 1 1 5 5 6 6 5 4 4 3 3 2 2 1 因而可以發現,“1 1 5 5 6 6 5 4 4 3 3 2 2 1”這串音符就成為了研究音律的關鍵。 小 Z 翻閱了眾多史料發現,過去的一首曲子的音調是不下降的 小 Z 想要知道對於一首給定的曲子,如何通過提高音調或者降低音調,將它的音調修改 的不下降, 而且使得修改幅度最大的那個音符的修改幅度盡量小。 即如果把一個包含 n 個音 符的曲子看做是一個正整數數列 A[1]…A[n], 那麽 目標是求另一個正整數數列 B[1]…B[n], 使得對於任意的 1≤i<n 有 B[i] ≤B[i+1], 而且使得 Ans = Max{|A[j]-B[j]|,1≤j≤n}盡量 小。 小 Z 很快就想清楚了做法,但是鑒於他還忙著寫詩, 所以這個任務就交給了你。

Input

由於數據規模可能較大,因此采用如下方式生成數據。

每個數據包含 6 個數:n,Sa,Sb,Sc,Sd,A[1],Mod,意為共有 n 個音符,第一個音符為 A[1]。 生成規則如下: 定義生成函數 F(x) = Sa*x^3 + Sb*x^2 + Sc*x + Sd; 那麽給出遞推公式 A[i] = F(A[i-1]) + F(A[i-2]),此處規定 A[0] = 0. 由於中間過程的數可能會特別大,所以要求每一步與 A 中的每個數都對一個給定的數 Mod 取模。

Output

輸出一行,包含一個正整數 Ans。

Sample Input

3 815 6901 3839 178 199 10007

Sample Output

1334

HINT

n≤5000000

對於 100%的數據, Sa,Sb,Sc,Sd,A[1] ≤10000, Mod≤1000000007 樣例中生成的數列為:
199 4568 1901,此時將 4568 修改為 3234,1901 也修改為 3234 即可,代價為 1334。

Solution

二分答案暴力判斷啊...

二分最後的答案,$check$的時候更新一個$max(a[i]-x,mx)$,如果$a[i]+x$都比目前的$mx$小的話顯然就無法構成不下降序列了

還有一點就是一定要註意乘法的溢出,$1ll$和$mod$要多用幾個

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std ;

#define N 5000010
int n , sa , sb , sc ,sd , mod ;
int a[ N ] ;

int F( int x ) {
    return ( ( ( 1ll * sa * x % mod * x % mod * x % mod + 1ll * sb * x % mod * x % mod ) % mod + 1ll * sc * x % mod ) % mod + 1ll * sd % mod ) % mod ;
}

bool check( int x ) {
    int mx = 0 ; 
    for( int i = 1 ; i <= n ; i ++ ) {
        mx = std::max( mx , a[ i ] - x ) ;
        if( a[ i ] + x < mx ) return 0 ;
    }
    return 1 ;
}

int main() {
    scanf( "%d%d%d%d%d%d%d" , &n , &sa , &sb , &sc , &sd , &a[ 1 ] , &mod ) ;
    a[ 0 ] = 0 ;
    for( int i = 2 ; i <= n ; i ++ ) {
        a[ i ] = F( a[ i - 1 ] ) + F( a[ i - 2 ] ) ;
        a[ i ] = a[ i ] % mod ;
    }
    int l = 0 , r = mod , ans = mod ;
    while( l <= r ) {
        int mid = ( l + r ) >> 1 ;
        if( check( mid ) ) r = mid - 1 , ans = mid ;
        else l = mid + 1 ;
    }
    printf( "%d\n" , ans ) ;
}

[BZOJ3613][Heoi2014]南園滿地堆輕絮 二分答案