[BZOJ 3613][Heoi2014]南园满地堆轻絮(贪心+二分)

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

Solution

其实是有线性做法的…不过我写的是二分加贪心,思路还是比较直接的,就是让每一个数在保持数列性质的情况下尽可能的小

从1到n递推,如果ai加上mid也没有达到last那说明这个mid在这一位已经不能完成

      否则可以完成这一位,如果ai减去mid仍大于last那么last=ai-mid,不然保持last的值(我们总可以把ai通过不超过mid的修改改为last)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int n,sa,sb,sc,sd,Mod,a[5000005];
int F(LL x)
{
    LL x2=(x*x)%Mod,x3=(x2*x)%Mod;
    return (((sa*x3)%Mod+(sb*x2)%Mod)%Mod+((sc*x)%Mod+sd)%Mod)%Mod;
}
int main()
{
    scanf("%d%d%d%d%d%d%d",&n,&sa,&sb,&sc,&sd,&a[1],&Mod);
    for(int i=2;i<=n;i++)
    a[i]=(F(a[i-1])+F(a[i-2]))%Mod;
    int l=0,r=Mod,ans=Mod;
    while(l<=r)
    {
        int mid=(l+r)>>1,last=a[1]-mid;bool f=1;
        for(int i=2;i<=n;i++)
        {
            if(a[i]+mid>=last)
            {if(a[i]-mid>last)last=a[i]-mid;}
            else {l=mid+1,f=0;break;}
        }
        if(f)r=mid-1,ans=mid;
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2017-06-09 17:19  Zars19  阅读(142)  评论(0编辑  收藏  举报