自己写的时候写了二维单调队列优化的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
qwq
int128 真香
#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 */