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. JS-根据身份证获取 出生日期和性别

    一.根据身份证获取出生日期和性别/** * 根据身份证获取出生日期(yyyy-MM-dd) * @param psidno * @returns {birthday:yyyy-MM-dd} * @co ...

  2. Spring Boot 加载application.properties顺序

    1.准备四份application.properties a.项目根目录下config/application.properties ,内容为:  test.user.name = a b.项目根目录 ...

  3. vue-cli3搭建的vue项目中使用jquery

    装包:npm install jquery --save 方式一 全局使用 1)main.js中引入 // jquery import $ from 'jquery' Vue.prototype.$ ...

  4. 力扣 - 232. 用栈实现队列.md

    目录 题目 思路 代码实现 复杂度分析 题目 请你仅使用两个栈实现先入先出队列.队列应当支持一般队列的支持的所有操作(push.pop.peek.empty): 实现 MyQueue 类: void ...

  5. 3.2spring源码系列----循环依赖源码分析

    首先,我们在3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖 中手写了循环依赖的实现. 这个实现就是模拟的spring的循环依赖. 目的是为了更容易理解spring源码 ...

  6. C++ 数据结构 3:树和二叉树

    1 树 1.1 定义 由一个或多个(n ≥ 0)结点组成的有限集合 T,有且仅有一个结点称为根(root),当 n > 1 时,其余的结点分为 m (m ≥ 0)个互不相交的有限集合T1,T2, ...

  7. Uipath_考证学习之路

    写在前面 第一次考证的时候,就是为了考证而考证,从网上获取了试题,修改了一下,就通过了,对 REFramework的了解甚少,经过几周的学习,决定赶在 4.30号考证收费之前再重新考一次. 原文章发表 ...

  8. Pandas_VBA_数据筛选比较

    Pandas与VBA筛选数据的比较 Author:Collin_PXY 需求: 将B列里值为Completed 和 Pending的A,B,D三列数据筛选出来,新建一个名为 Filited_data的 ...

  9. waf 引擎 云原生平台tproxy 实现调研

    了解了基本 云原生架构,不清楚的查看之前的文章:https://www.cnblogs.com/codestack/p/13914134.html 现在来看看云原生平台tproxy waf引擎串联实现 ...

  10. Java 类型信息详解和反射机制

    本文部分摘自 On Java 8 RTTI RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限 ...