解析
自己写的时候写了二维单调队列优化的64分
一次过还是可以满意了啦
正解的关键结论是最优的方案的最后一段一定尽可能的短
原因嘛…显然 贪心的想,再最后一段的段首可以往前放的情况下肯定是要往前放的,这样代价更小,同时对后面的选取也更加有利
这个性质是可以递归的
考虑如何求以i结尾的最后一段的最短长度
设以
i
i
i为末端的最短段的上一段的段尾在
p
o
s
i
pos_i
posi
设
s
i
s_i
si是
[
1
,
i
]
[1,i]
[1,i]的前缀和
那么
p
o
s
i
pos_i
posi就是满足:
s
i
−
s
j
>
=
s
j
−
s
p
o
s
j
s_i-s_j>=s_j-s_{pos_j}
si−sj>=sj−sposj
的
j
j
j的最大值
移一下项:
s
i
>
=
2
∗
s
j
−
s
p
o
s
j
s_i>=2*s_j-s_{pos_j}
si>=2∗sj−sposj
这个就可以用单调队列来维护了
时间复杂度
O
(
n
)
O(n)
O(n)
关于最后的12分
需要高精
然而我上压位了还是T
qwqint128 真香
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=4e7+100;
const double eps=1e-6;
const int mod=1333331;
inline ll read() {
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
int pos[N];
ll sum[N];
int q[N],st,ed;
#define calc(o) (sum[o]*2-sum[pos[o]])
const int key=1e4;
struct bign{
ll a[155],len;
};
inline bign trans(ll o){
bign res;res.len=0;
while(o){
res.a[++res.len]=o%key;
o/=key;
}
return res;
}
inline bign operator * (bign a,bign b){
bign res;memset(res.a,0,sizeof(res.a));
for(register int i=1;i<=a.len;i++){
for(register int j=1;j<=b.len;j++) res.a[i+j-1]+=a.a[i]*b.a[j];
}
res.len=a.len+b.len;
int p=0;
for(register int i=1;i<=res.len;i++){
res.a[i]+=p;
p=res.a[i]/key;res.a[i]-=key*p;
if(i==res.len&&p) res.len++;
}
while(!res.a[res.len]) res.len--;
return res;
}
inline bign operator + (bign a,bign b){
bign res;memset(res.a,0,sizeof(res.a));
int top=a.len>b.len?a.len:b.len,p=0;
for(register int i=1;i<=top;i++){
res.a[i]+=a.a[i]+b.a[i]+p;
p=res.a[i]/key;res.a[i]-=key*p;
if(i==top&&p) top++;
}
res.len=top;
return res;
}
__int128 res;
int b[N],p[N],l[N],r[N],w=(1<<30)-1;
void write(__int128 x){
if(x>9) write(x/10);
putchar('0'+x%10);
return;
}
int main() {
n=read();register int T=read();
int a;
if(T==0) for(register int i=1;i<=n;i++) a=read(),sum[i]=sum[i-1]+a;
else{
ll x=read(),y=read(),z=read();
b[1]=read(),b[2]=read(),m=read();
for(register int i=1;i<=m;i++){
p[i]=read();l[i]=read();r[i]=read();
}
int pl=1;
for(register int i=3;i<=n;i++) b[i]=(1ll*x*b[i-1]+1ll*y*b[i-2]+z)&w;
for(register int i=1;i<=n;i++){
if(i>p[pl]) ++pl;
a=(b[i]%(r[pl]-l[pl]+1))+l[pl];sum[i]=sum[i-1]+a;
}
}
for(register int i=1;i<=n;i++){
while(st<ed&&sum[i]>=calc(q[st+1])) st++;
pos[i]=q[st];
while(st<=ed&&calc(q[ed])>=calc(i)) ed--;
q[++ed]=i;
//printf("i=%d pos=%d\n",i,pos[i]);
}
for(register int pl=n;pl;pl=pos[pl]){
res=res+(__int128)(sum[pl]-sum[pos[pl]])*(sum[pl]-sum[pos[pl]]);
}
//printf("%d\n",res.len);
write(res);
return 0;
}
/*
100 1
123 456 789 12345 6789 3
2000000 123456789 987654321
7000000 234567891 876543219
10000000 456789123 567891234
*/