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