经典模型:在n个点中选k个点,要求两两不相邻,且总权值最大/最小。

  做法:用双向链表串起来,把所有点丢进堆里,选择一个点的时候把它左右两个点从双向链表和堆中去除,然后把这个点的权值加进ans,出堆后改为左右两边的权值-当前权值重新入堆,重复k次,ans即为答案

  原理:左右两边的权值-当前权值相当于这个点不选,改为选左右两边的点,并且多选了一个点,重复k次后必然取到k个点

  三道同类型题

  bzoj1150:显然一段网线肯定接在相邻的两个点,于是把相邻的点的距离求出来,问题就变成经典模型了

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=1e9;
struct poi{int pos,dis;};
priority_queue<poi>q;
bool operator<(poi a,poi b){return a.dis>b.dis;}
int n,k,a[maxn],dis[maxn],pre[maxn],next[maxn];
ll ans;
bool v[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
inline void del(int x)
{
int l=pre[x],r=next[x];
pre[x]=next[x]=;
next[l]=r;pre[r]=l;
}
int main()
{
read(n);read(k);
for(int i=;i<=n;i++)read(a[i]);
for(int i=;i<n;i++)dis[i]=a[i+]-a[i],q.push((poi){i,dis[i]});dis[]=dis[n]=inf;
for(int i=;i<n;i++)pre[i]=i-,next[i]=i+;
for(int i=;i<=k;i++)
{
poi t=q.top();
while(v[t.pos])q.pop(),t=q.top();
ans+=t.dis;v[pre[t.pos]]=v[next[t.pos]]=;
dis[t.pos]=dis[pre[t.pos]]+dis[next[t.pos]]-dis[t.pos];
q.pop();q.push((poi){t.pos,dis[t.pos]});
del(pre[t.pos]);del(next[t.pos]);
}
printf("%lld\n",ans);
return ;
}

  bzoj2151:双向链表首尾串起来,问题就变成经典模型了

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=1e9;
struct poi{int pos,dis;};
priority_queue<poi>q;
bool operator<(poi a,poi b){return a.dis<b.dis;}
int n,k,a[maxn],dis[maxn],pre[maxn],next[maxn];
ll ans;
bool v[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
inline void del(int x)
{
int l=pre[x],r=next[x];
pre[x]=next[x]=;
next[l]=r;pre[r]=l;
}
int main()
{
read(n);read(k);
if(k>n>>)return puts("Error!"),;
for(int i=;i<=n;i++)read(dis[i]),q.push((poi){i,dis[i]});
for(int i=;i<=n;i++)pre[i]=i-,next[i]=i+;pre[]=n;next[n]=;
for(int i=;i<=k;i++)
{
poi t=q.top();
while(v[t.pos])q.pop(),t=q.top();
ans+=t.dis;v[pre[t.pos]]=v[next[t.pos]]=;
dis[t.pos]=dis[pre[t.pos]]+dis[next[t.pos]]-dis[t.pos];
q.pop();q.push((poi){t.pos,dis[t.pos]});
del(pre[t.pos]);del(next[t.pos]);
}
printf("%lld\n",ans);
return ;
}

  bzoj2288:

  这题比较复杂。首先可以发现正数连续的一段和负数连续的一段要取肯定是都得同时取的,那么就可以把连续的同正负的数缩成一个了。然后如果正数个数不大于k,直接取所有正数即可。如果正数个数大于k,我们考虑舍弃一些正数,或者选择一些负数。只要将所有数取绝对值,问题就变成经典模型了。为什么呢?

  我们选择的是总权值最小的数,如果他是个正数,相当于舍弃,如果是负数,相当于把左右两端的正数连成一段。显然不可能同时选两个相邻的数,否则一定是正负一起选,那负数完全可以不选,因为既然你要丢弃这个正数,为何还要选择一个负数呢,选择负数的作用只有连接左右两端的正数。

  因此,这个题也能转化为经典模型,就可以写了。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=1e9;
struct poi{int pos,dis;};
priority_queue<poi>q;
bool operator<(poi a,poi b){return a.dis>b.dis;}
int n,m,flag,N,now,l,r,ans;
int a[maxn],s[maxn],pre[maxn],next[maxn];
bool v[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
inline void del(int x)
{
int l=pre[x],r=next[x];
pre[x]=next[x]=;
pre[r]=l;next[l]=r;
}
int main()
{
read(n);read(m);
for(int i=;i<=n;i++)read(a[i]);
int l=,r=n;
while(a[l]<=&&l<=n)l++;
while(a[r]<=&&r)r--;
for(int i=l;i<=r;)
{
if(a[i]>=)flag=;else flag=-;
for(now=;flag*a[i]>=&&i<=r;i++)now+=a[i];
s[++N]=now;
}
for(int i=;i<=N;i+=)ans+=s[i];
if(m>=(N+)>>)return printf("%d\n",ans),;
for(int i=;i<=N;i++)q.push((poi){i,s[i]=(s[i]>?s[i]:-s[i])});
for(int i=;i<=N;i++)pre[i]=i-,next[i]=i+;s[]=inf;s[N+]=inf;
int up=((N+)>>)-m;
for(int i=;i<=up;i++)
{
poi t=q.top();
while(v[t.pos])q.pop(),t=q.top();q.pop();
s[t.pos]=s[pre[t.pos]]+s[next[t.pos]]-s[t.pos];
ans-=t.dis;q.push((poi){t.pos,s[t.pos]});
v[pre[t.pos]]=v[next[t.pos]]=;
del(pre[t.pos]);del(next[t.pos]);
}
printf("%d\n",ans);
return ;
}

bzoj 1150&2151&2288(双向链表+堆)(贪心)的更多相关文章

  1. BZOJ 1029: [JSOI2007]建筑抢修 堆+贪心

    1029: [JSOI2007]建筑抢修 Description 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有 ...

  2. BZOJ 1150--数据备份(链表&堆&贪心)

    1150: [CTSC2007]数据备份Backup Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2572  Solved: 1038[Submit ...

  3. [BZOJ 1150] [CTSC2007] 数据备份Backup 【贪心 + 链表】

    题目链接:BZOJ - 1150 题目分析 可以看出,我们选的 k 条边一定是相邻两点之间的线段.我们可以将每条边看成一个点,那么我们就是要在 n-1 个点中选出互不相邻的 k 个,使它们的和最小. ...

  4. [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)

    [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆) 题面 给出一个长度为n的序列,选k段长度在L到R之间的区间,一个区间的值等于区间内所有元素之的和,使得k个区间的值之和最大.区 ...

  5. 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)

    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...

  6. BZOJ_2802_[Poi2012]Warehouse Store_堆+贪心

    BZOJ_2802_[Poi2012]Warehouse Store_堆+贪心 Description 有一家专卖一种商品的店,考虑连续的n天. 第i天上午会进货Ai件商品,中午的时候会有顾客需要购买 ...

  7. BZOJ_1150_[CTSC2007]数据备份Backup_堆+贪心

    BZOJ_1150_[CTSC2007]数据备份Backup_堆+贪心 Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏 ...

  8. P4053 [JSOI2007]建筑抢修 堆贪心

    思路:堆贪心 提交:1次 题解: 先按时间\(sort\),然后如果能修就直接扔堆里,不能修取堆顶比一下时间长短,把时间短的扔进堆: #include<cstdio> #include&l ...

  9. HDU5124lines题解-堆+贪心的一个新方法

    题目链接 https://cn.vjudge.net/problem/HDU-5124 胡扯 感觉说新方法好像有点不太好,但是翻了十几篇博客都是清一色离散化之类的... 为什么会做这道题呢?因为前几天 ...

随机推荐

  1. Ping隧道

    1.研究原因: 校园内网的探索,校内电子图书馆资源的利用,认证校园网 2.目的: 内网服务器:在一台因防火墙等原因仅限icmp数据通过的 公网服务器 : 建立icmp 隧道链接,  并在公网服务器上进 ...

  2. Selenium自动化测试第二天(下)

    如有任何学习问题,可以添加作者微信:lockingfree 目录 Selenium自动化测试基础 Selenium自动化测试第一天(上) Selenium自动化测试第一天(下) Selenium自动化 ...

  3. selenium自动化测试资源整理

    1. 所有版本chrome下载 是不是很难找到老版本的chrome?博主收集了几个下载chrome老版本的网站,其中哪个下载的是原版的就不得而知了. http://www.slimjet.com/ch ...

  4. 【form】 表单组件说明

    form表单组件 1)将form组件内的用户输入的<switch/> <input/> <checkbox/> <slider/> <radio/ ...

  5. ElasticSearch 论坛搜索查询语句

    概述 研究论坛搜索如何综合时间和TF/IDF权重. 自定义权重计算的效率问题 数据结构 假设有一个论坛的搜索 字段包括: subject:标题 message:内容 dateline:发布时间 tag ...

  6. Bitcoin: A Peer-to-Peer Electronic Cash System

    Bitcoin: A Peer-to-Peer Electronic Cash System Satoshi Nakamoto October 31, 2008 Abstract A purely p ...

  7. Jamie and Alarm Snooze

    Description Jamie loves sleeping. One day, he decides that he needs to wake up at exactly hh: mm. Ho ...

  8. <Android>spinner/AutoCompleteTextView绑定适配器

    position = (Spinner)findViewById(R.id.position); String[] str = {"CEO","CFO",&qu ...

  9. [TUTORIAL]How to setup SP_Flash_Tool_Linux (MTK/MediaTek Soc)

    转自:https://forum.xda-developers.com/general/rooting-roms/tutorial-how-to-setup-spflashtoollinux-t316 ...

  10. [计算机网络] C++模拟telnet登陆SMTP服务发送邮件过程

    在百度文库中的<使用telnet协议收发邮件>,我们可以很清楚地看到如何通过telnet来进行发送邮件,下面是一些需要用到的命令,通过以下命令可以很容易实现邮件发送功能.为了更好地理解其中 ...