P4105 [HEOI2014] 南园满地堆轻絮 题解

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;
}
posted @ 2025-12-09 22:02  Creativexz  阅读(3)  评论(0)    收藏  举报