题目描述
小 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 很快就想清楚了做法,但是鉴于他还忙着写诗, 所以这个任务就交给了你。

思路:简单二分就行。先生成数组,然后二分差值,将数组的最大值设置为上界,下界设为0,然后对于每次可能的差值进行check,数组前面的元素在合法的情况下越小越好,当出现元素比上一个元素小很多时,就返回false。
代码:

#include <bits/stdc++.h>
using namespace std;
long long A[10000050],n,sa,sb,sc,sd,Mod,l=0,r=0;
long long F(long long x)
{
    return (sa*x%Mod*x%Mod*x%Mod+sb*x%Mod*x%Mod+sc*x%Mod+sd)%Mod;
}
void gen()
{
    A[0]=0;
    scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&sa,&sb,&sc,&sd,&A[1],&Mod);
    r=max(r,A[1]);
    for(int i=2;i<=n;i++){
        A[i]=(F(A[i-1])+F(A[i-2]))%Mod;
        r=max(r,A[i]);
        //printf("%lld ",A[i]);
    }//printf("\n");
}
long long B[10000050];
bool check(long long x)
{
    //printf("aa%lld\n",x);
    B[0]=0;
    for(int i=1;i<=n;i++){
        if(B[i-1]-A[i]>x)return false;
        if(A[i]>=B[i-1])B[i]=max(B[i-1],A[i]-x);
        else B[i]=min(B[i-1],A[i]+x);
        //printf("%lld ",B[i]);
    }

    return true;
}
int main(){
    gen();
    long long ans=0;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }else l=mid+1;
        //printf("\n");
    }
    printf("%lld\n",ans);
    return 0;
}