#dp or 贪心+堆#CF704B Ant Man
分析(dp)
考虑到对于一个排列单独抽出 \(1\sim i\) 可能会分成若干段,而贡献一定是固定的,不会影响之后的选择。
首先 \(a,c\) 加上 \(x\),\(b,d\) 减去 \(x\),那么贡献就转换为
\(\begin{cases}i<j,d_i+a_j\\i>j,c_i+b_j\end{cases}\)
同样考虑从小到大插入每一个数,
设 \(dp[i][j]\) 表示前 \(i\) 个数分成 \(j\) 段的最小权值。
若 \(i=St\),那么可以新开一段或者补到开头位置。
\(dp[i][j]=\min\{dp[i-1][j-1]+d_i,dp[i-1][j]+c_i(j>0)\}\)
若 \(i=Ed\),同理 \(dp[i][j]=\min\{dp[i-1][j-1]+b_i,dp[i-1][j]+a_i(j>0)\}\)
如果 \(i\) 不为开头或结尾,那么可以新开一段,合并两段,或者接在一段的开头或者结尾(但是不能替代 \(St\) 和 \(Ed\))
新开一段就是 \(dp[i][j]=\min\{dp[i-1][j-1]+b_i+d_i\}\)
合并两段就是 \(dp[i][j]=\min\{dp[i-1][j+1]+a_i+c_i\}\)
接到开头就是 \(dp[i][j]=\min\{dp[i-1][j]+b_i+c_i\}(j>(i>St))\)
接到末尾就是 \(dp[i][j]=\min\{dp[i-1][j]+a_i+d_i\}(j>(i>Ed))\)
最后答案就是 \(dp[n][1]\)
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
const int N=5011; typedef long long lll;
int n,st,ed,x[N],a[4][N]; lll dp[2][N];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void Min(lll &x,lll y){x=x<y?x:y;}
int main(){
n=iut(),st=iut(),ed=iut();
for (int i=1;i<=n;++i) x[i]=iut();
for (int i=1;i<=n;++i) a[0][i]=iut()+x[i];
for (int i=1;i<=n;++i) a[1][i]=iut()-x[i];
for (int i=1;i<=n;++i) a[2][i]=iut()+x[i];
for (int i=1;i<=n;++i) a[3][i]=iut()-x[i];
memset(dp[0],0x3f,sizeof(dp[0])),dp[0][0]=0;
for (int i=1;i<=n;++i){
memset(dp[i&1],0x3f,sizeof(dp[i&1]));
if (i==st){
for (int j=(i>ed);j<i;++j){
if (j) Min(dp[i&1][j],dp[(i&1)^1][j]+a[2][i]);
Min(dp[i&1][j+1],dp[(i&1)^1][j]+a[3][i]);
}
}else if (i==ed){
for (int j=(i>st);j<i;++j){
if (j) Min(dp[i&1][j],dp[(i&1)^1][j]+a[0][i]);
Min(dp[i&1][j+1],dp[(i&1)^1][j]+a[1][i]);
}
}else{
for (int j=(i>st)+(i>ed);j<i;++j){
if (j>1) Min(dp[i&1][j-1],dp[(i&1)^1][j]+a[0][i]+a[2][i]);
Min(dp[i&1][j+1],dp[(i&1)^1][j]+a[1][i]+a[3][i]);
if (j>(i>st)) Min(dp[i&1][j],dp[(i&1)^1][j]+a[2][i]+a[1][i]);
if (j>(i>ed)) Min(dp[i&1][j],dp[(i&1)^1][j]+a[0][i]+a[3][i]);
}
}
}
return !printf("%lld",dp[n&1][1]);
}
分析(贪心)
首先填入首尾,为了有最小值出现,同时将 1 填入。
还是一样从小到大填数,不过先考虑加上 \(a_i+c_i\),
其它数必然是接在中间,考虑直接用选完的数接上,
那么就是要找到 \(b_i-a_i\) 或者是 \(d_i-c_i\) 的最小值,用堆维护即可。
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
const int N=5011; typedef long long lll;
int n,st,ed,x[N],Cnt; lll ans,heap[N<<1],a[4][N];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void Swap(lll &x,lll &y){x^=y^=x^=y;}
void Push(lll W){
heap[++Cnt]=W;
for (int x=Cnt;x>1;x>>=1)
if (heap[x]<heap[x>>1])
Swap(heap[x],heap[x>>1]);
else return;
}
void Pop(){
heap[1]=heap[Cnt--];
for (int x=1;(x<<1)<=Cnt;){
int y=x<<1|1;
if (y>Cnt||heap[y]>=heap[y-1]) --y;
if (heap[x]<=heap[y]) return;
Swap(heap[x],heap[y]),x=y;
}
}
int main(){
n=iut(),st=iut(),ed=iut();
for (int i=1;i<=n;++i) x[i]=iut();
for (int i=1;i<=n;++i) a[0][i]=iut()+x[i];
for (int i=1;i<=n;++i) a[1][i]=iut()-x[i];
for (int i=1;i<=n;++i) a[2][i]=iut()+x[i];
for (int i=1;i<=n;++i) a[3][i]=iut()-x[i];
if (st>1&&ed>1) ans=a[2][st]+a[1][1]+a[3][1]+a[0][ed];
else ans=(st>ed)?(a[2][st]+a[1][ed]):(a[3][st]+a[0][ed]);
for (int i=2;i<=n;++i)
if (i==st) Push(a[3][i]-a[2][i]);
else if (i==ed) Push(a[1][i]-a[0][i]);
else{
ans+=a[0][i]+a[2][i];
if (i<st) Push(a[1][i]-a[0][i]);//可以与st接在一起
if (i<ed) Push(a[3][i]-a[2][i]);//可以与ed接在一起
ans+=heap[1],Pop();
if (i>st) Push(a[1][i]-a[0][i]);
if (i>ed) Push(a[3][i]-a[2][i]);
}
return !printf("%lld",ans);
}
#dp or 贪心+堆#CF704B Ant Man的更多相关文章
- 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)
题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...
- 【贪心+堆】XMU 1584 小明的烦恼
题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1584 题目大意: 给n(n<=100 000)个任务的耗时和截至时间,问最少不能 ...
- BZOJ_2151_种树_贪心+堆+链表
BZOJ_2151_种树_贪心+堆 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编 ...
- BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表
BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐 ...
- BZOJ_1029_ [JSOI2007]建筑抢修_贪心+堆
BZOJ_1029_ [JSOI2007]建筑抢修_贪心+堆 Description 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是 ...
- 【bzoj4425】[Nwerc2015]Assigning Workstations分配工作站 贪心+堆
题目描述 佩内洛普是新建立的超级计算机的管理员中的一员. 她的工作是分配工作站给到这里来运行他们的计算研究任务的研究人员. 佩内洛普非常懒惰,不喜欢为到达的研究者们解锁机器. 她可以从在她的办公桌远程 ...
- 【bzoj1029】[JSOI2007]建筑抢修 贪心+堆
题目描述 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建 ...
- 【bzoj2802】[Poi2012]Warehouse Store 贪心+堆
题目描述 有一家专卖一种商品的店,考虑连续的n天.第i天上午会进货Ai件商品,中午的时候会有顾客需要购买Bi件商品,可以选择满足顾客的要求,或是无视掉他.如果要满足顾客的需求,就必须要有足够的库存.问 ...
- BZOJ 1724: [Usaco2006 Nov]Fence Repair 切割木板 贪心 + 堆 + 反向思考
Description Farmer John想修理牧场栅栏的某些小段.为此,他需要N(1<=N<=20,000)块特定长度的木板,第i块木板的长度为Li(1<=Li<=50, ...
- P1095 守望者的逃离——DP?贪心?
https://www.luogu.org/problem/P1095 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变.守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大 ...
随机推荐
- GDI实现透明菜单位图
case WM_CONTEXTMENU: { m_hMenu = CreatePopupMenu(); g_BitMap = (HBITMAP)LoadImage(NULL, L"1.bmp ...
- Qt实用技巧:Qt从QtCreator更换为VS开发Qt所需要注意的坑
前言 基本都是使用QtCreator开发,使用vs进行一下开发,记录从QtCreator换成VS所遇到的注意的坑. VS装对应的Qt版本助手配置Qt版本 VS装番茄助手 这里 ...
- python列表操作的大O效率
- 正则表达式re模块---day18
1.匹配单个字符 import re lst = re.findall(正则表达式,要匹配的字符串) 返回的是列表,按照正则表达式匹配到的内容都扔到列表中 # ### 1.预定义字符集 # \d 匹配 ...
- Redis加Lua脚本实现分布式锁
先讲一下为什么使用分布式锁: 在传统的单体应用中,我们可以使用Java并发处理相关的API(如ReentrantLock或synchronized)来实现对共享资源的互斥控制,确保在高并发情况下同一时 ...
- CXP2.0的相机是否可以使用CXP1.1的Grabber
可以 答案是肯定的. 目前CXP共有2个发布版本: 2011年发布CXP1.1 2021年发布CXP2.1,向后兼容,新标准增加了同步功能.数据率放大了一倍. 只要是符合CXP标准.接插件匹配,那么C ...
- 【Azure Developer】Java代码访问Key Vault Secret时候的认证问题,使用 DefaultAzureCredentialBuilder 或者 ClientSecretCredentialBuilder
问题描述 使用Java SDK获取Key Vault Secret机密信息时,需要获取授权.通常是使用AAD的注册应用(Client ID, Tenant ID, Client Secret)来获取 ...
- OPPO 自研大规模知识图谱及其在数智工程中的应用
导读:OPPO 知识图谱是 OPPO 数智工程系统小布助手团队主导.多团队协作建设的自研大规模通用知识图谱,目前已达到数亿实体和数十亿三元组的规模,主要落地在小布助手知识问答.电商搜索等场景. 本文主 ...
- Find The Multiple 题解
Find The Multiple The long-lost Sunday is coming again, and the ACM Laboratory Elimination Competi ...
- DuiLib 一个window的皮肤库 C++ 项目,打包小,比较纯正主流的大制作
https://github.com/duilib/duilib 从 火柴 那个软件 发现的这个库