1 条题解
-
0
先考虑暴力,设 表示最后一段分割在区间 上,那么最暴力的就是 枚举,我们发现 对于每一个 可选的 集应该是不断增大的,于是我们可以对于每一个 单调队列,复杂度 。
其实我们可以配合贪心通过一些数学性质来解决这个问题或者打表,就像方差那题一样。对于这题显然越大的数,平方越大,也就是 ,于是我们需要保证最后一段划分尽可能小,也就是这么多段尽可能接近或者说划分更多段。
于是我们设出 表示前 个数的答案, 表示最后一段划分的和。这样只需要每次找到最大的 满足 进行转移即可。即 ,相同变量在一侧,单调队列即可。注意 不一定大于 ,只是要求大于前一段并不是大于上一个位置。
时间复杂度 。
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=4e7+10; const int maxm=1e5+10; const int mod=(1<<30); long long pre[maxn],g[maxn]; int top=0; int q[maxn],p[maxm],l[maxm],r[maxm],b[maxn],a[60]; inline long long calc(int x){ return 2*pre[x]-pre[g[x]]; } inline long long val(int x){ return pre[x]-pre[g[x]]; } void print(__int128 ans){ while(ans){ a[++top]=ans%10; ans/=10; } while(top) cout<<a[top--]; } int main(){ int n,type; cin>>n>>type; if(!type){ pre[0]=0; for(int i=1;i<=n;i++){ int x; cin>>x; pre[i]=pre[i-1]+x; } }else{ int x,y,z,m; cin>>x>>y>>z>>b[1]>>b[2]>>m; for(int i=1;i<=m;i++) cin>>p[i]>>l[i]>>r[i]; for(int i=3;i<=n;i++) b[i]=(1ll*b[i-1]*x+1ll*b[i-2]*y+z)%mod; for(int i=1;i<=m;i++) for(int j=p[i-1]+1;j<=p[i];j++){ x=b[j]%(r[i]-l[i]+1)+l[i]; pre[j]=pre[j-1]+x; } } q[0]=0; int l=1,r=1; q[1]=0; for(int i=1;i<=n;i++){ while(pre[i]>=calc(q[l+1])&&l<r) l++; g[i]=q[l]; while(calc(i)<=calc(q[r])&&l<=r) r--; q[++r]=i; } int P=n; __int128 ans=0,mul=1; while(P){ mul=val(P); mul=mul*mul; ans=ans+mul; P=g[P]; } print(ans); return 0; }
- 1
信息
- ID
- 1998
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者