Part 1

先来看一个错误的贪心做法:假设当前结尾的一段和为 \(a\),等待加入结尾的一段和为 \(b\),现在要处理新进来的数 \(c\)。

  1. \(a\leq b\),将 \(a\) 算入答案,将 \(b\) 加入结尾。
  2. \(a+b\leq c\),将 \(b\) 并入 \(a\)。
  3. \(a\leq b+c\),此时将 \(a\) 算入答案。

比如说这组数据就能叉掉它:

10 0
5 1 2 1 1 1 1 1 2 3

我们划分成了 \(5+5+8\),而显然有一组更优的方案 \(5+6+7\) 和一组最优的方案 \(6+6+6\)。

时间复杂度 \(O\left(n\right)\),期望得分 \(0\),实际得分 \(8pts\)。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i,x,y)for(i=x;i<=(y);i++)
ll read()
{
ll A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
int main()
{
// freopen("partition.in","r",stdin);
// freopen("partition.out","w",stdout);
int n,i;
bool type;
ll b,a,c,s;
n=read(),type=read(),b=read();
a=s=0;
For(i,2,n)
{
c=read();
if(a<=b)
{
s+=a*a;
a=b;
b=c;
}
else if(a+b<=c)a=a+b,b=c;
else if(a<=b+c)
{
s+=a*a;
a=b+c;
if(i++<n)b=read();
else
{
b=0;
break;
}
}
else b=b+c;
}
cout<<s+(a<=b?a*a+b*b:(a+b)*(a+b));
return 0;
}

Part 2

发现贪心完全无法考虑到后面的情况,考虑 DP。

令 \(f_{i,j}\) 表示前 \(i\) 个数,最后一段长度为 \(j\) 的最小代价。

转移方程也很好写 \(f_{i,j}=\max\left\{\left.f_{i-j,k}+\left(sum_i-sum_{i-j}\right)^2\right|sum_i-sum_{i-j}\geq sum_{i-j}-sum_{i-j-k}\right\}\)。

时间复杂度 \(O\left(n^3\right)\),期望得分 \(36pts\),实际得分 \(36pts\)。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 5005
#define Min(x,y)((x)<(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
ll f[N][N],a[N],b[N];
int main()
{
// freopen("partition.in","r",stdin);
// freopen("partition.out","w",stdout);
bool type;
int n,i,j,k;
ll mn=4000000000000000000ll;
scanf("%d%d",&n,&type);
For(i,1,n)scanf("%lld",&a[i]);
For(i,1,n)b[i]=b[i-1]+a[i];
For(i,1,n)
{
For(j,1,i-1)f[i][j]=4000000000000000000ll;
f[i][i]=b[i]*b[i];
}
For(i,1,n-1)
For(j,1,i)
For(k,1,n-i)
if(b[i+k]-b[i]>=b[i]-b[i-j])f[i+k][k]=Min(f[i+k][k],f[i][j]+(b[i+k]-b[i])*(b[i+k]-b[i]));
For(i,1,n)mn=Min(mn,f[n][i]);
printf("%lld",mn);
return 0;
}

Part 3

打表可以发现一个规律:合法情况下,\(j\) 最小,\(f_{i,j}\) 一定最小。

感性理解一下就是每段的和比较小,平方和比较小。也就是能多分段。

证明我会了再来补。

用上这个结论后就比较 easy 了。向前找到第一个合法的转移点然后转移过来。

时间复杂度 \(O\left(n^2\right)\),期望得分 \(64pts\),实际得分 \(64pts\)。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 5005
#define For(i,x,y)for(i=x;i<=(y);i++)
#define Down(i,x,y)for(i=x;i>=(y);i--)
ll a[N],s[N],f[N];
int main()
{
// freopen("partition.in","r",stdin);
// freopen("partition.out","w",stdout);
int n,m,i,j;
scanf("%d%d",&n,&m);
For(i,1,n)
{
scanf("%d",&a[i]);
a[i]+=a[i-1];
Down(j,i-1,0)
if(a[i]-a[j]>=s[j])break;
s[i]=a[i]-a[j];
f[i]=f[j]+s[i]*s[i];
}
printf("%lld",f[n]);
return 0;
}

Part 4

用单调队列维护所有可能有用的转移点。

不是越后面的转移点越优吗,为什么不能用指针扫过去?因为转移点的合法程度不是单调的,前面的点不合法,后面的点可能就合法了。

时间复杂度 \(O\left(n\right)\),期望得分 \(88pts\),实际得分 \(88pts\)。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 500005
#define For(i,x,y)for(i=x;i<=(y);i++)
int que[N];
ll g[N],a[N],f[N];
int read()
{
int A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
int main()
{
bool type;
int n,i,head=0,tail=1;
n=read(),type=read();
For(i,1,n)a[i]=a[i-1]+read();
For(i,1,n)
{
while(head<tail&&a[i]-a[que[head+1]]>=g[que[head+1]])head++;
f[i]=f[que[head]]+(a[i]-a[que[head]])*(a[i]-a[que[head]]);
g[i]=a[i]-a[que[head]];
while(head<=tail&&a[i]+g[i]<=a[que[tail]]+g[que[tail]])tail--;
que[++tail]=i;
}
cout<<f[n];
return 0;
}

Part 5

需要手写高精度。我比较懒就直接用 __int128 了(然而考试的时候并不能用)。注意不要开高精数组计算答案,开个 int 数组记一下转移点即可,最后用高精变量回上去计算,不然直接 MLE。当然还得卡卡常。

调不出来可以看看数据生成有没有写错,被卡了好久。

时间复杂度 \(O\left(n\right)\),期望得分 \(100pts\),实际得分 \(88\sim 100pts\)。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 40000005
#define Mod 1073741824
#define For(i,x,y)for(i=x;i<=(y);i++)
ll a[N];
__int128 f;
int que[N],pre[N];
int read()
{
int A;
bool K;
char C;
C=A=K=0;
while(C<'0'||C>'9')K|=C=='-',C=getchar();
while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
return(K?-A:A);
}
void write(__int128 X)
{
if(X<0)putchar('-'),X=-X;
if(X>9)write(X/10);
putchar(X%10|48);
}
void solve(int x)
{
while(x)f+=__int128(a[x]-a[pre[x]])*(a[x]-a[pre[x]]),x=pre[x];
}
int main()
{
// freopen("partition.in","r",stdin);
// freopen("partition.out","w",stdout);
bool type;
int n,i,head=0,tail=1;
n=read(),type=read();
if(!type)
For(i,1,n)a[i]=a[i-1]+read();
else
{
int x,y,z,u,v,m,p,l,r,last=1;
x=read(),y=read(),z=read();
u=a[1]=read(),v=a[2]=read(),m=read();
while(m--)
{
p=read(),l=read(),r=read();
For(i,last,p)
if(i<3)a[i]=a[i-1]+a[i]%(r-l+1)+l;
else
{
a[i]=(1LL*x*v+1LL*y*u+z)%Mod;
u=v;
v=a[i];
a[i]=a[i]%(r-l+1)+l+a[i-1];
}
last=i;
}
}
For(i,1,n)
{
while(head<tail&&a[i]-a[que[head+1]]>=a[que[head+1]]-a[pre[que[head+1]]])head++;
pre[i]=que[head];
while(head<=tail&&(a[i]<<1)-a[pre[i]]<=(a[que[tail]]<<1)-a[pre[que[tail]]])tail--;
que[++tail]=i;
}
solve(n);
write(f);
return 0;
}

P5665 划分的更多相关文章

  1. 【CSP-S 2019】【洛谷P5665】划分【单调队列dp】

    前言 \(csp\)时发现自己做过类似这道题的题目 : P4954 [USACO09Open] Tower of Hay 干草塔 然后回忆了差不多\(15min\)才想出来... 然后就敲了\(88p ...

  2. 洛谷 P5665 [CSP-S2019] 划分

    链接: P5665 题意: 给出 \(n\) 个整数 \(a_i\) ,你需要找到一些分界点 \(1 \leq k_1 \lt k_2 \lt \cdots \lt k_p \lt n\),使得 \( ...

  3. [P5665][CSP2019D2T2] 划分

    先说说部分分做法吧 1.\(n \leq 10\) 指数级瞎草都可以2333 2.\(n \leq 50\) 好像并没有什么做法-也许给剪枝的人部分分吧 3.\(n \leq 400\) 这个复杂度是 ...

  4. [LeetCode] Partition List 划分链表

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...

  5. SWMM模型子汇水区划分的几种方法

    子汇水区的划分是SWMM模型建模的主要步骤之一,划分的好坏对结果精度有比较大的影响.概括来讲,子汇水区的划分有以下几种思路: (1)根据管网走向.建筑物和街道分布,直接人工划分子汇水区.这个方法适用于 ...

  6. 等价类划分方法的应用(jsp)

    [问题描述] 在三个文本框中输入字符串,要求均为1到6个英文字符或数字,按submit提交. [划分等价类] 条件1: 字符合法; 条件2: 输入1长度合法; 条件3: 输入2长度合法: 条件4: 输 ...

  7. Java上等价类划分测试的实现

    利用JavaFx实现对有效等价类和无效等价类的划分: 代码: import javafx.application.Application;import javafx.event.ActionEvent ...

  8. ENode框架Conference案例分析系列之 - 上下文划分和领域建模

    前面一片文章,我介绍了Conference案例的核心业务,为了方便后面的分析,我这里再列一下: 业务描述 Conference是这样一个系统,它提供了一个在线创建会议以及预订会议座位的平台.这个系统的 ...

  9. Cesium原理篇:2最长的一帧之网格划分

    上一篇我们从宏观上介绍了Cesium的渲染过程,本章延续上一章的内容,详细介绍一下Cesium网格划分的一些细节,包括如下几个方面: 流程 Tile四叉树的构建 LOD 流程 首先,通过上篇的类关系描 ...

随机推荐

  1. Foundation 用于开发响应

    Foundation 用于开发响应式的 HTML, CSS and JavaScript 框架. Foundation 是一个易用.强大而且灵活的框架,用于构建基于任何设备上的 Web 应用. Fou ...

  2. Django model总结(上)

    Django model是django框架中处于比较核心的一个部位,准备分三个博客从不同的方面分别进行阐述,本文为<上篇>,主要对[a]Model的基本流程,比如它的创建,迁移等:默认行为 ...

  3. C# 9.0 新特性预览 - init-only 属性

    C# 9.0 新特性预览 - init-only 属性 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章 ...

  4. Jenkins配置,tomacat版本输出乱码和页面打开报404的问题

    1.打开tomact下的startup.bat,tomcat版本控制台中文输出乱码,解决方法是去tomacat安装路径下的conf目录,打开logging.properties文件,将java.uti ...

  5. MongoDB 监控 --- MongoDB基础用法(八)

    MongoDB 监控 在你已经安装部署并允许MongoDB服务后,你必须要了解MongoDB的运行情况,并查看MongoDB的性能.这样在大流量得情况下可以很好的应对并保证MongoDB正常运作. M ...

  6. K8S 使用 SideCar 模式部署 Filebeat 收集容器日志

    对于 K8S 内的容器日志收集,业内一般有两种常用的方式: 使用 DaemonSet 在每台 Node 上部署一个日志收集容器,用于收集当前 Node 上所有容器挂载到宿主机目录下的日志 使用 Sid ...

  7. 一个Task.Factory.StartNew的错误用法

    同事写了这样一段代码: FactoryStartNew类: using System; using System.Collections.Generic; using System.Linq; usi ...

  8. 云计算管理平台之OpenStack网络服务neutron

    一.简介 neutron的主要作用是在openstack中为启动虚拟机实例提供网络服务,对于neutron来讲,它可以提供两种类型的网络:第一种是provider network,这种网络就是我们常说 ...

  9. Luogu P2447 [SDOI2010]外星千足虫

    题意 给定 \(n\) 个变量和 \(m\) 个异或方程,求最少需要多少个才能确定每个变量的解. \(\texttt{Data Range:}1\leq n\leq 10^3,1\leq m\leq ...

  10. 力扣 - 768. 最多能完成排序的块II

    目录 题目 思路 代码实现 复杂度分析 题目 这个问题和"最多能完成排序的块"相似,但给定数组中的元素可以重复,输入数组最大长度为2000,其中的元素最大为10**8. arr是一 ...