P4105 [HEOI2014] 南园满地堆轻絮
Description
给你一个长度为 \(n\) 的正整数序列 \(a\),让你构造一个单调不降的正整数序列 \(b\),使得下面式子的值尽量小。
\[\max_{i=1}^{n} |a_i-b_i|
\]
其中 \(n\le 5\times 10^6\)。
Solution
注意到经典的“最小值最大”,考虑二分。
我们从对比 \(a_i\) 和 \(b_i\) 的角度来看,\(|a_i-b_i|\) 其实就是指你构造出的 \(b_i\) 和 \(a_i\) 的偏差值,我们要让这个东西最小。
假设对于一对 \(a_i\) 和 \(b_i\),我们有一个符合条件且最小的偏差值 \(x\),那么 \(x+1\) 一定符合条件,因此有单调性,可以二分。
然后就好搞了。对于每一个 \(i\) ,我们二分 \(a_i\) 的最小偏差值。如果减去最小偏差值后得到的 \(b_i\) 不能满足条件(让 \(b\) 序列单调不降),那就让 \(b_i=b_{i-1}\),如果可行那就直接赋值。
复杂度为 \(O(n\log n)\),可以通过。
#include<bits/stdc++.h>
using namespace std;
long long n,Sa,Sb,Sc,Sd,mod,a[5000005],b[5000005];
inline long long calc(int x){return (((Sa*x%mod*x%mod*x%mod+Sb*x%mod*x%mod)%mod+Sc*x%mod)%mod+Sd)%mod;
}
inline bool check(int x){for(int i=1;i<=n;i++){b[i]=a[i];}for(int i=1;i<=n;i++){if(b[i]+x<b[i-1]){return 0;}if(b[i]<b[i-1]){b[i]=b[i-1];}else{b[i]=max(b[i-1],b[i]-x);}}return 1;
}
signed main(){cin>>n>>Sa>>Sb>>Sc>>Sd>>a[1]>>mod;for(int i=2;i<=n;i++){a[i]=(calc(a[i-1])+calc(a[i-2]))%mod;}int l=0,r=6e9;int minx=INT_MAX;while(l<=r){int mid=(l+r)/2;if(check(mid)){r=mid-1;minx=min(minx,mid);}else{l=mid+1;}}cout<<minx<<endl;return 0;
}