解析
自己写的时候写了二维单调队列优化的64分
一次过还是可以满意了啦
正解的关键结论是最优的方案的最后一段一定尽可能的短
原因嘛…显然 贪心的想,再最后一段的段首可以往前放的情况下肯定是要往前放的,这样代价更小,同时对后面的选取也更加有利
这个性质是可以递归的
考虑如何求以i结尾的最后一段的最短长度
设以iii为末端的最短段的上一段的段尾在posipos_iposi
设sis_isi是[1,i][1,i][1,i]的前缀和
那么posipos_iposi就是满足:
si−sj>=sj−sposjs_i-s_j>=s_j-s_{pos_j}si−sj>=sj−sposj
的jjj的最大值
移一下项:
si>=2∗sj−sposjs_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
*/