HEOI2014 南国满地堆轻絮

时间:2021-06-27 19:58:34

题目链接:戳我

就是二分一个数,之后记录一个前缀max,然后和当前数做差再/2即可。(因为我们要使得原来的序列变成不下降序列,所以当然是要控制一个上限,以达到后面较小数能以尽可能小的代价增加)

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 5000010
using namespace std;
int n,sa,sb,sc,sd,mod;
int a[MAXN];
inline int f(int x)
{
int cur_ans1=1ll*x*x%mod*x%mod*sa%mod;
int cur_ans2=1ll*x*x%mod*sb%mod;
int cur_ans3=1ll*x*sc%mod;
return (1ll*cur_ans1+cur_ans2+cur_ans3+sd)%mod;
}
inline bool check(int x)
{
int maxx=0,cur_ans=0;
for(int i=1;i<=n;i++)
{
maxx=max(maxx,a[i]);
cur_ans=max(cur_ans,(maxx-a[i]+1)/2);
}
// printf("x=%d cur_ans=%d\n",x,cur_ans);
if(cur_ans<=x) return true;
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
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-2])+f(a[i-1]))%mod;
// for(int i=1;i<=n;i++) printf("a[%d]=%d\n",i,a[i]);
int l=0,r=mod,ans;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}