搬讲义~~~~

题目1:玩具装箱(bzoj1010)

Description

P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1…N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.

Input

第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1
 
经典的决策单调性问题··但也可以用斜率优化····维护一个栈,栈中维护每个决策以及用到它的最优状态的左右区间··每次先更新状态然后将其作为决策二分查找替换栈中决策即可···
另外由于决策单调性是建立在平行四边形不等式的基础上的··而那个东西证起来很麻烦····做题的时候也不容易反应过来··所以尽量还是打表来寻找决策单调性··
 
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=5e4+;
long long sum[N],f[N];
struct node
{
int l,r,pos;
}que[N];
int n,L,head,tail;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
inline long long get(int j,int i)
{
return f[j]+(long long)(sum[i]-sum[j]+i-j--L)*(sum[i]-sum[j]+i-j--L);
}
inline int find(node a,int b)
{
int le=a.l,ri=a.r;
while(le<=ri)
{
int mid=(le+ri)/;
if(get(b,mid)<get(a.pos,mid)) ri=mid-;
else le=mid+;
}
return le;
}
inline void work()
{
head=,tail=;
node temp;temp.l=,temp.r=n,temp.pos=;que[++tail]=temp;
for(int i=;i<=n;i++)
{
while(que[head].r<i) head++;
f[i]=get(que[head].pos,i);
if(head>tail||get(i,n)<get(que[tail].pos,n))
{
while(head<=tail&&(get(i,que[tail].l)<get(que[tail].pos,que[tail].l))) tail--;
if(head<=tail)
{
int t=find(que[tail],i);
que[tail].r=t-;
node temp;temp.l=t;temp.r=n;temp.pos=i;
que[++tail]=temp;
}
else
{
node temp;temp.l=i,temp.r=n,temp.pos=i;
que[++tail]=temp;
}
}
}
}
int main()
{
//freopen("a.in","r",stdin);
n=R();L=R();
for(int i=;i<=n;i++) sum[i]=R(),sum[i]+=sum[i-];
work();cout<<f[n]<<endl;
return ;
}

题目2:土地购买(bzoj1597)

Description

农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

Input

* 第1行: 一个数: N

* 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

Output

* 第一行: 最小的可行费用.

Sample Input

4
100 1
15 15
20 5
1 100

输入解释:

共有4块土地.

Sample Output

500

HINT

FJ分3组买这些土地: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15 plot. 每组的价格分别为100,100,300, 总共500.

这道题首先将土地按x降序排序···可以容易发现那些x和y都会小于某一个土地的土地是肯定是多余无用的···所以将这些点排除后剩余土地肯定是按照x降序··y升序排列的,于是可以推出dp方程

其中f[n]表示的是购买前n块土地的最小花费···方程满足单调性····于是就和上面一道题一样了······其实这道题也可以用斜率优化来做·····后面会提到

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=5e4+;
struct node
{
int x,y;
}a[N],b[N];
struct node1
{
int l,r,pos;
}que[N];
inline bool cmp(node a,node b)
{
if(a.x==b.x) return a.y>b.y;
return a.x>b.x;
}
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
int n,tot;
long long f[N];
inline long long calc(int i,int j)
{
return f[j]+(long long)b[i].y*b[j+].x;
}
inline int find(node1 a,int b)
{
int le=a.l,ri=a.r,ans=a.r+;
while(le<=ri)
{
int mid=(le+ri)/;
if(calc(mid,b)<calc(mid,a.pos)) ri=mid-,ans=mid;
else le=mid+;
}
return ans;
}
inline bool dp()
{
int head=,tail=;
node1 temp;temp.l=;temp.r=tot;temp.pos=;que[++tail]=temp;
for(int i=;i<=tot;i++)
{
while(que[head].r<i) head++;
f[i]=calc(i,que[head].pos);
if(calc(tot,i)<calc(tot,que[tail].pos))
{
while(head<=tail&&calc(que[tail].l,i)<calc(que[tail].l,que[tail].pos)) tail--;
if(head<=tail)
{
int t=find(que[tail],i);
que[tail].r=t-;
node1 temp;temp.l=t,temp.r=tot,temp.pos=i;que[++tail]=temp;
}
else
{
node1 temp;temp.l=i;temp.r=tot;temp.pos=i;que[++tail]=temp;
}
}
}
}
int main()
{
// freopen("a.in","r",stdin);
n=R();
for(int i=;i<=n;i++)
a[i].x=R(),a[i].y=R();
sort(a+,a+n+,cmp);b[++tot]=a[];int maxx=a[].y;
for(int i=;i<=n;i++)
if(a[i].y>maxx) maxx=a[i].y,b[++tot]=a[i];
dp();cout<<f[tot]<<endl;
return ;
}
 

题目1:生产产品(vijo1243)

描述

在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行。由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同。机器i完成第j个步骤的时间为T[i,j]。把半成品从一台机器上搬到另一台机器上也需要一定的时间K。同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤。也就是说,如果有一台机器连续完成了产品的L个步骤,下一个步骤就必须换一台机器来完成。现在,dd_engi的OI商店有史以来的第一个产品就要开始生产了,那么最短需要多长时间呢?
某日Azuki.7对跃动说:这样的题目太简单,我们把题目的范围改一改
对于菜鸟跃动来说,这是个很困难的问题,他希望你能帮他解决这个问题

格式

输入格式

第一行有四个整数M, N, K, L
下面的N行,每行有M个整数。第I+1行的第J个整数为T[J,I]。

输出格式

输出只有一行,表示需要的最短时间。

样例1

样例输入1

3 2 0 2
2 2 3
1 3 1

样例输出1

4

限制

1s

提示

对于50%的数据,N<=5,L<=4,M<=10000
对于100%的数据,N<=5, L<=50000,M<=100000

来源

第一届“OI商店杯” dd_engi原创题目

很妙的一道单调队列的题···,之前其实是做过的···

首先容易想到朴素的dp方程:f[i][j]表示第i个机器生产了第j个过程且前j个过程已经完成生产的最小花费···容易得到:

dp[i][j]=min{dp[k][j']+sum[i][j]-sum[i][j']}+K

其中sum为预处理出的前缀和···j-l<j'<j

由此我们将sum[i][j]提到外面后我们不难发现大括号号中的部分实际上是关于j'的一个函数····因此可以按照上述步骤用单调队列解决:

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<deque>
using namespace std;
const int M=1e5+;
const int N=;
const int inf=0x7f7f7f7f;
deque<int> dque[N][N];
int n,m,K,sum[M][N],l,dp[M][N];
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline int calc(int i,int k,int j)
{
return dp[k][j]-sum[k][i];
}
int main()
{
m=R(),n=R(),K=R(),l=R();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
sum[j][i]=R(),sum[j][i]+=sum[j-][i];
memset(dp,inf,sizeof(dp));
for(int i=;i<=n;i++) dp[][i]=;
for(int j=; j<=m; ++j)
{
for(int i=; i<=n; ++i)
for(int k=; k<=n; ++k)
if(i!=k) while(!dque[i][k].empty()&&(j-dque[i][k].front())>l) dque[i][k].pop_front();
for(int i=; i<=n; ++i)
for(int k=; k<=n; ++k)
if(i!=k)
{
int a=,b=;
if(!dque[i][k].empty()) a=calc(i,dque[i][k].front(),k);
b=sum[j][i]+K;
dp[j][i]=min(dp[j][i],a+b);
}
for(int i=; i<=n; ++i)
for(int k=; k<=n; ++k)
if(i!=k)
{
while(!dque[i][k].empty()&&(calc(i,dque[i][k].back(),k)>=calc(i,j,k))) dque[i][k].pop_back();
dque[i][k].push_back(j);
}
}
int ans=inf;
for(int i=;i<=n;i++) ans=min(ans,dp[m][i]);
cout<<ans-K<<endl;
return ;
}

题目1:Max Sum Plus Plus(hdu1024)

Problem Description

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S1, S2, S3, S4 ... Sx, ... Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function sum(i, j) = Si + ... + Sj (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + ... + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).

But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead. ^_^

Input

Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 ... Sn.
Process to the end of file.

Output

Output the maximal summation described above in one line.

Sample Input

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

Sample Output

6 8

Hint

Huge input, scanf and dynamic programming is recommended.

 
用f[i][j]表示取了i段且第i段最后一个数取的是num[j]时最大的和···推出朴素dp方程:

f[i][j]=max{f[i][j-1]+num[j],f[i-1][k]+num[j]}

其中k小于j·····

不难发现每当我们先枚举i再枚举j时此时的f[i][j-1]只与上一层i-1有关,所以我们可以降维··用f[j]来代表此时的f[i][j]那么可以推出dp方程

f[j]=max(f[j-1]+num[j],temp[j-1]+num[j]);

其中temp为在枚举i-1时已经处理出的上一层的最小值

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+;
const int inf=0x3f3f3f3f;
inline int R()
{
char c;int f=,i=;
for(c=getchar();(c<''||c>'')&&c!='-';c=getchar());
if(c=='-') i=-,c=getchar();
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f*i;
}
int num[N],n,m;
long long f[N],temp[N];
int main()
{
//freopen("a.in","r",stdin);
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(temp,,sizeof(temp));
memset(f,,sizeof(f));
for(int i=;i<=n;i++) num[i]=R();
f[]=temp[]=;
for(int i=;i<=m;i++)
{
long long maxx=-inf;
for(int j=i;j<=n;j++)
{
f[j]=max(f[j-]+num[j],temp[j-]+num[j]);
temp[j-]=maxx;maxx=max(maxx,f[j]);
}
}
long long ans=-inf;
for(int i=m;i<=n;i++) ans=max(ans,f[i]);
cout<<ans<<endl;
}
return ;
}

题目2:Max Sum Plus Plus Plus

Problem Description

给定一个由n个正整数组成的整数序列

a1 a2 a3 ... an

求按先后次序在其中取m段长度分别为l1、l2、l3...lm的不交叠的连续整数的和的最大值。

Input

第一行是一个整数n(0 ≤ n ≤ 1000),n = 0表示输入结束
第二行的第一个数是m(1 ≤ m ≤ 20),
第二行接下来有m个整数l1,l2...lm。
第三行是n个整数a1, a2, a2 ... an.

Output

输出m段整数和的最大值。

Sample Input

3
2 1 1
1 2 3
4
2 1 2
1 2 3 5
0

Sample Output

5
10

和上面一道题几乎是差不多的···只是注意此时f[i][j]表示的是取第i段,第i段的最后一个数字是num[j]时的最大价值··

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cctype>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=;
const int M=;
int numn[N],numm[M],n,m;
long long sumn[N],summ[M],f[N],maxx[N];
inline int R()
{
char c;int f=,i=;
for(c=getchar();(c<''||c>'')&&c!='-';c=getchar());
if(c=='-') i=-,c=getchar();
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f*i;
}
int main()
{
//freopen("a.in","r",stdin);
while(true)
{
n=R();if(!n) break;m=R();
memset(sumn,,sizeof(sumn));memset(summ,,sizeof(summ));
memset(f,,sizeof(f));memset(maxx,,sizeof(maxx));
for(int i=;i<=m;i++) numm[i]=R(),summ[i]=numm[i]+summ[i-];
for(int i=;i<=n;i++) numn[i]=R(),sumn[i]=numn[i]+sumn[i-];
for(int i=;i<=m;i++)
{
for(int j=summ[i];j<=n;j++)
{
if(j==summ[i]) f[j]=sumn[j];
else f[j]=maxx[j-numm[i]]+sumn[j]-sumn[j-numm[i]];
}
for(int j=summ[i];j<=n;j++)
{
if(j==summ[i]) maxx[j]=f[j];
else maxx[j]=max(maxx[j-],f[j]);
}
}
long long anss=-1e+;
for(int i=summ[m];i<=n;i++) anss=max(anss,f[i]);
cout<<anss<<endl;
}
return ;
}

算法复习——1D/1Ddp优化的更多相关文章

  1. C#冒泡算法复习

    C#冒泡算法复习 冒泡算法的意思:每一趟找到一个最小或最大的数放到最后面,比较总数的n-1次(因为比较是2个双双比较的) 第一层循环表示进行比较的次数,总共要比较(数的)-1次 (因为比较是2个双双比 ...

  2. 谷歌蜂鸟算法对网站seo优化有何影响

    http://www.wocaoseo.com/thread-89-1-1.html       谷歌在过去三个月里,非常低调的推出了蜂鸟算法,据谷歌技术员表示,此种方法一出,将影响90%网站的排名, ...

  3. C语言排序算法复习

    排序算法有很多种,这里在复习和分析的基础上,做一个自己的总结: 首先要知道有哪些排序算法,google一下,有云C语言7大经典排序算法(也有8大).主要包括冒泡排序,快速排序,选择排序,插入排序,希尔 ...

  4. [Algorithm] 群体智能优化算法之粒子群优化算法

    同进化算法(见博客<[Evolutionary Algorithm] 进化算法简介>,进化算法是受生物进化机制启发而产生的一系列算法)和人工神经网络算法(Neural Networks,简 ...

  5. K-Means聚类和EM算法复习总结

    摘要: 1.算法概述 2.算法推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 k-means算法是一种得到最广泛使用的聚类算法. 它是将各个聚类子集内 ...

  6. 揽货最短路径解决方案算法 - C# 蚁群优化算法实现

    需求为(自己编的,非实际项目): 某配送中心进行揽货,目标客户数为50个客户,配送中心目前的运力资源如下: 现有车辆5台 单台运力最大行驶距离200千米 单台运力最大载重公斤1吨 问:运力怎样走法才能 ...

  7. KMP算法复习【+继续学习】

    离NOIP还剩12天,本蒟蒻开始准备复习了. 先来个KMP[似乎我并没有写过KMP的blog] KMP KMP算法是解决字符串匹配问题的一个算法,主要是单对单的字符串匹配加速,时间复杂度O(m + n ...

  8. DJ 算法的队列优先优化

    DJ算法就是求单源最短路的算法,但是时间复杂度不太理想,所以在此献上用最小堆来优化的算法. 如果不懂优先队列可以先去看STL分类关于优先队列的介绍: ///POJ 2387为例 #include< ...

  9. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

随机推荐

  1. CF Gym 100637A Nano alarm-clocks

    题意:给你一些钟的时间,只可以往后调, 问最少调的时间总和是多少 题解:因为肯定是调到某个出现过时间的,只要枚举时间,在维护一个前缀和快速计算出时间总和就行了. #include<cstdio& ...

  2. 在DataGridView控件中验证数据输入

    实现效果: 知识运用: DataGridView控件的公共事件CellValidating //将System.Windows.Forms.DataGridViewCellValidatingEven ...

  3. Form组件的验证流程及扩展(钩子)

    Form组件的验证流程及扩展(钩子) 常用的form class TestForm(Form): t1 = fields.CharField( widget=widgets.Textarea # 输入 ...

  4. Python——流程控制语句

    if语句 条件进行判断,满足,则执行里面 的内容:不满足,则执行if循环下面的语句 基本语法: if 判断条件: 满足后执行语句 1 如果:女人的年龄>30岁,那么:叫阿姨 age_of_gir ...

  5. 新手 WordPress主题制作全过程

    WordPress主题制作全过程(一):基础准备 前言: 我想大多数使用WordPress的朋友都喜欢去尝试新的主题,但是换来换去,总是找不到那么一款适合自己的,让人很郁闷.于是很多人萌生了修改现有主 ...

  6. mysql中影响数据库性能的因素讲解

    mysql中影响数据库性能的因素讲解 在本篇文章中我们给大家讲述了mysql中影响性能的因素以及相关知识点内容,有兴趣的朋友参考下 关于数据库性能的故事 面试时多多少少会讲到数据库上的事情,“你对数据 ...

  7. Android深度探索总结

    Android深度探索前四章总结 通过这几章的学习真实体会到“移植”的概念:为特定设备定制Android的过程,但是移植的过程中开发最多的就是支持各种硬件设备的Linux驱动程序,本章对Android ...

  8. Postgres-XL的限制

    Postgres-XL是基于PostgreSQL的一个分布式数据库. 相比于PostgreSQL,XL的表的数据是可以分布到不同的datanode上的,对存在于不同的datanode上的数据进行处理, ...

  9. 【启发式搜索】Codechef March Cook-Off 2018. Maximum Tree Path

    有点像计蒜之道里的 京东的物流路径 题目描述 给定一棵 N 个节点的树,每个节点有一个正整数权值.记节点 i 的权值为 Ai.考虑节点 u 和 v 之间的一条简单路径,记 dist(u, v) 为其长 ...

  10. 再生龙备份还原linux系统

    相关下载: Clonezilla再生龙:http://sourceforge.net/projects/clonezilla/files/clonezilla_live_stable/ tuxboot ...