题解:P5665 [CSP-S2019] 划分
MoCaRabbit · · 题解
首先对于两个段
于是需要在
设
因为多分段,所以
我们将
设
得出代码。
#include<bits/stdc++.h>
using namespace std;
int n,FW_number;
int a[100010];
__int128 s[100010];
__int128 dp[5010];
inline void write(__int128 x){
if(x<0){
putchar('-');
write(-x);
return;
}
if(x<10){
putchar(x%10+'0');
return;
}
write(x/10);
putchar((x%10)^48);
}
int l[5010];
int main() {
cin>>n>>FW_number;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];//前缀和
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
if(s[i]-s[j]>=l[j] && dp[i]>dp[j]+(s[i]-s[j])*(s[i]-s[j])) dp[i]=dp[j]+(s[i]-s[j])*(s[i]-s[j]),l[i]=s[i]-s[j];
write(dp[n]);
return 0;
}
记录。
单调队列优化
如果
设
这个转移的条件有
移项可得
又因为
于是我们建立单调队列,内装候选项。
转移时直接将不满足条件的排出,插入时将比此状态劣(也就是
最后直接计算答案即可。
时间复杂度
注意最后使用 __int128 记录答案,开多了会爆空间,少了会答案错误。
#include<bits/stdc++.h>
using namespace std;
int n,FW_number;
int a[40000010];
long long s[40000010];
inline void write(__int128 x){
if(x<0){
putchar('-');
write(-x);
return;
}
if(x<10){
putchar(x%10+'0');
return;
}
write(x/10);
putchar((x%10)^48);
}
int pre[40000010];
int q[40000010],head,tail;
int b[40000010],p[100010];
inline long long l(int x){
return s[x]-s[pre[x]];
}
void read(){
long long x,y,z,m;
cin>>x>>y>>z>>b[1]>>b[2]>>m;
for(int i=3;i<=n;i++) b[i]=(x*b[i-1]+y*b[i-2]+z)%(1<<30);
for(int i=1;i<=m;i++){
long long l,r;
cin>>p[i]>>l>>r;
for(int j=p[i-1]+1;j<=p[i];j++) a[j]=(b[j]%(r-l+1))+l;
}
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
}
int main() {
cin>>n>>FW_number;
if(!FW_number) for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
else read();
head=1,tail=0;
q[++tail]=0;
for(int i=1;i<=n;i++){
while(head<tail && s[i]-s[q[head+1]]>=l(q[head+1])) head++;
pre[i]=q[head];
while(head<tail && s[q[tail]]-s[i]>=l(i)-l(q[tail])) tail--;
q[++tail]=i;
}
__int128 ans=0;
for(int i=n;i;i=pre[i]) ans+=(__int128)l(i)*l(i);
write(ans);
return 0;
}