2020/10/30 模拟赛 序列
Description
淘淘在研究极差,即可重集的最大值减最小值(这个定义应该都知道吧)。 蓝蓝有一个数列 $a_1,a_2,\cdots ,a_n$。他想考考淘淘是否真的理解了极差,就让淘淘把他划分为若干子区间(可以退化为一个数,但不能退化为空集),并最大化这些子区间极差之和。 由于他的数列太长了,他用某种方法来表示这个序列,详情请见输入格式。 又由于他的数列太长了,他只需要淘淘告诉他这个最大值的和。
Solution
题中要求一个序列划分为数段,每一段的极差之和
发现如果有一段不单调,可以将其划分得到更优的答案;如果一段单调,继续划分不会使答案更优
从前到后扫数组,考虑每一位作为一个单调区间的最小值或最大值两种情况
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,x,y,z,b[10000005],a[10000005],m; long long ans,maxx,minn; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } int main() { n=read(),x=read(),y=read(),z=read(),b[1]=read(),b[2]=read(),m=read(); for(int i=3;i<=n;i++) { b[i]=(1ll*x*b[i-1]+1ll*y*b[i-2]+z)%(1<<30); } for(int i=1,j=1;i<=m;i++) { int p=read(),l=read(),r=read(); while(j<=p) { a[j]=b[j]%(r-l+1)+l,++j; } } minn=-a[1],maxx=a[1]; for(int i=1;i<=n;i++) { ans=max(minn+a[i],maxx-a[i]); minn=max(minn,ans-a[i+1]); maxx=max(maxx,ans+a[i+1]); } printf("%lld\n",ans); return 0; }