矩阵dp

  这里是矩阵dp,不是矩阵乘法优化dp。

  矩阵上的dp好像也没什么特殊的?大概有一个套路就是从上向下,从左向右进行dp吧。


  

  首先第一道题好像不是矩阵dp...

  1005 矩阵取数游戏:https://www.luogu.org/problemnew/show/P1005

  题意概述:在一个矩阵里面取数,每次从每行的左或右取一个数,并乘以$2^i$,$i$是取数的次数。直到取完为止,求最大得分。

  看起来是道非常复杂的矩阵dp题,理性分析一下可以发现每一行之间并没有什么关系,所以分行做完以后再加起来就可以啦。那么在每一行内怎么做呢?像区间dp一样,用$dp[i][j]$表示取到剩下区间$[i][j]$时的最大得分。

  然后再加上高精...

  

 # include <cstdio>
# include <iostream>
# include <cstring>
# define R register int using namespace std; int n,m,j;
int len,a[][];
int dp[][][];
int P[][],ansc[][],ans[];
int t[]; void add (int *a,int *b)
{
len=max(a[],b[])+;
for (R i=;i<=len;++i)
{
a[i]+=b[i];
a[i+]+=a[i]/;
a[i]%=;
}
while (a[len]==&&len) len--;
a[]=len;
} void M (int *a,int *b)
{
if(a[]>b[]) return ;
if(b[]>a[])
{
len=b[];
for (R i=;i<=len;++i)
a[i]=b[i];
return ;
}
len=a[];
for (R i=len;i>=;--i)
{
if(a[i]>b[i]) return ;
if(a[i]==b[i]) continue;
if(a[i]<b[i])
{
for (R j=;j<=len;++j)
a[j]=b[j];
return ;
}
}
} void mul(int *a,int *b,int c)
{
len=b[];
for (R i=;i<=len;++i)
a[i]=b[i]*c;
len+=;
for (R i=;i<=len;++i)
a[i+]+=a[i]/,a[i]%=;
while (a[len]==&&len) len--;
a[]=len;
} int main()
{
scanf("%d%d",&n,&m);
P[][]=P[][]=;
for (R i=;i<=;++i)
{
P[i][]=P[i-][]*;
len=P[i][];
for (R j=;j<=len;++j)
P[i][j]=P[i-][j]*;
for (R j=;j<=len;++j)
P[i][j+]+=P[i][j]/,P[i][j]%=;
while (P[i][len]==&&len) len--;
P[i][]=len;
}
for (R i=;i<=n;++i)
for (R j=;j<=m;++j)
scanf("%d",&a[i][j]);
for (R c=;c<=n;++c)
{
memset(dp,,sizeof(dp));
memset(ansc,,sizeof(ansc));
for (R k=m;k>=;k--)
for (R i=;i+k-<=m;i++)
{
j=i+k-;
memset(t,,sizeof(t));
mul(t,P[m-k+],a[c][i]);
add(t,dp[i][j]);
M(dp[i+][j],t);
memset(t,,sizeof(t));
mul(t,P[m-k+],a[c][j]);
add(t,dp[i][j]);
M(dp[i][j-],t);
}
for (R i=;i<=m;++i)
{
mul(ansc[i],P[m],a[c][i]);
add(ansc[i],dp[i][i]);
}
for (R i=;i<=m;++i)
M(ansc[],ansc[i]);
add(ans,ansc[]);
}
len=ans[];
for (R i=len;i>=;--i)
printf("%d",ans[i]);
if(len==) printf("");
return ;
}

矩阵取数游戏


  我发现我对矩阵这两个字大概是有什么误解吧,有的题不知道怎么归类,因为开了二维数组就进到矩阵dp这一栏里了?

  垃圾陷阱:https://www.luogu.org/problemnew/show/P1156

  题意概述:奶牛掉进了垃圾井,当有垃圾扔下来时,他可以吃掉,也可以堆放起来,问最短的出去时间,如果出不去,求最长的存活时间。

  这道题有一个坑点,奶牛的生命值为0时还可以吃东西,堆垃圾,甚至跑出去...

  用dp[i][j]表示用前i个物品,堆放高度为j时的最大生命值(能活到什么时候)。如果将一个垃圾堆起来,那它并不能续命,所以$dp[i][j]=max(dp[i-1][ j-h[i] ],dp[i][j])$;如果把垃圾吃了,那可以续一点命,但是不能增加高度,所以$dp[i][j]=max(dp[i][j],dp[i-1][j]+f[a])$.再处理一下边界就可以啦。

  

# include <cstdio>
# include <iostream>
# include <algorithm>
# include <cstring> using namespace std; struct rubbi
{
int t,f,h;
}a[]; bool cmp(rubbi a,rubbi b)
{
return a.t<b.t;
} int d,g,ans=1e7;
int dp[][]; int main()
{
int S=;
scanf("%d%d",&d,&g);
for (int i=;i<=g;i++)
scanf("%d%d%d",&a[i].t,&a[i].f,&a[i].h);
sort(a+,a++g,cmp);
memset(dp,-,sizeof(dp));
dp[][]=;
for (int i=;i<=g;i++)
for (int j=;j<=d+;j++)
{
if(dp[i-][j-a[i].h]!=-&&j>=a[i].h&&dp[i-][j-a[i].h]>=a[i].t)
dp[i][j]=max(dp[i][j],dp[i-][j-a[i].h]);
if(dp[i-][j]!=-&&dp[i-][j]>=a[i].t) dp[i][j]=max(dp[i][j],dp[i-][j]+max(a[i].f,));
if(dp[i][j]!=-&&j>=d)
{
ans=min(ans,a[i].t);
}
if(dp[i][j]!=-)
S=max(S,dp[i][j]);
}
if(ans!=1e7)
printf("%d",ans);
else
printf("%d",S);
return ;
}

垃圾陷阱


  

  奶牛浴场:https://www.luogu.org/problemnew/show/P1578

  题意概述:在一个有障碍的矩形中选出一个最大的子矩形,使得内部没有障碍点 (边界上可以有) 。

  以前就做过这道题目,结果今天一看被Hack了,才发现之前学的那个方法不大对...这道题有两种做法,但是因为这题的障碍较少,所以第一种方法比较优也比较快。

  https://wenku.baidu.com/view/728cd5126edb6f1aff001fbb.html (扔完链接就跑路)

  具体实现就不写了,毕竟论文讲的非常详细非常好,记录一下要注意的地方吧。

   ·在矩形的四个顶点分别建立虚点。

   ·有的矩形是左边有一个障碍点,有的是右边有一个障碍点,所以正着做一遍,反着做一遍。

   ·有的矩形左右都没有障碍点,所以按照另一维坐标排序,将左右边界定为矩形的两边再统计一次答案。

  ·如果某一个障碍点和这次扫描的起点纵坐标相同就直接break。感觉好像会把一些合法情况排除掉呢,但是并不会。因为这两个点现在到了一条直线上,如果有合法答案必然会作为上边界或下边界,一个矩形有四个顶点,所以这样的情况必然还会在其他时间被枚举到。

  

 # include <cstdio>
# include <iostream>
# include <algorithm>
# define R register int using namespace std; int l,w,n,h,t,le,ans=;
struct nod
{
int x,y;
}P[]; bool cmp1(nod a,nod b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
} bool cmp2(nod a,nod b)
{
return a.y<b.y;
} int main()
{
scanf("%d%d",&l,&w);
scanf("%d",&n);
for (R i=;i<=n;++i)
scanf("%d%d",&P[i].x,&P[i].y);
P[n+].x=; P[n+].y=;
P[n+].x=l; P[n+].y=;
P[n+].x=; P[n+].y=w;
P[n+].x=l; P[n+].y=w;
sort(P+,P++n,cmp1);
for (R i=;i<=n+;++i)
{
h=,t=w;
le=P[i].x;
for (R j=i+;j<=n+;++j)
{
if(P[j].x==le) continue;
ans=max(ans,(t-h)*(P[j].x-le));
if(P[j].y==P[i].y) break;
if(P[j].y>P[i].y) t=min(t,P[j].y);
if(P[j].y<P[i].y) h=max(h,P[j].y);
}
}
for (R i=n+;i>=;--i)
{
h=,t=w;
le=P[i].x;
for (R j=i-;j>=;j--)
{
if(P[j].x==le) continue;
ans=max(ans,(t-h)*(le-P[j].x));
if(P[j].y==P[i].y) break;
if(P[j].y>P[i].y) t=min(t,P[j].y);
if(P[j].y<P[i].y) h=max(h,P[j].y);
}
}
sort(P+,P++n,cmp2);
for (R i=;i<=n+;++i)
ans=max(ans,l*(P[i+].y-P[i].y));
printf("%d",ans);
return ;
}

奶牛浴场

  [HAOI2007]理想的正方形:https://www.luogu.org/problemnew/show/P2216

  题意概述:在一个a*b的矩形中选出一个n*n的正方形,使得正方形内的最大值减去最小值最小,求这个最小值。$1<=a,b<=2000$

  二维线段树!显然是可以的,但是没有必要。观察数据范围可以发现$O(N^3)$的暴力就可以跑过去,这就给了我们很大的启发,可以只统计区间的最大最小值,行与行之间暴力统计,既然是要求区间的最大最小值就可以用单调队列啦。还有一个很不错的做法可以进一步提高程序速度,拒绝暴力统计,在单调队列的基础上再开行的单调队列,就$N^2$了,但是感觉挺麻烦的就没写。

  

 // luogu-judger-enable-o2
# include <cstdio>
# include <cstring>
# include <iostream>
# define R register int
# define inf using namespace std; const int maxa=;
struct nod
{
int key,val;
};
nod q1[maxa],q2[maxa];
int a,b,n,h1,h2,t1,t2,big,sma;
int g[maxa][maxa];
int minn[maxa][maxa],maxx[maxa][maxa];
int ans=inf; void ins1 (int i,int j)
{
int x=g[i+n-][j+n-];
while (q1[h1].key<j&&h1<=t1) h1++;
while (q1[t1].val<=x&&h1<=t1) t1--;
q1[++t1].key=j+n-;
q1[t1].val=x;
} void ins2 (int i,int j)
{
int x=g[i+n-][j+n-];
while (q2[h2].key<j&&h2<=t2) h2++;
while (q2[t2].val>=x&&h2<=t2) t2--;
q2[++t2].key=j+n-;
q2[t2].val=x;
} int main()
{
scanf("%d%d%d",&a,&b,&n);
for (R i=;i<=a;++i)
for (R j=;j<=b;++j)
scanf("%d",&g[i][j]);
for (R i=;i<=a;++i)
for (R j=;j<=b;++j)
minn[i][j]=inf;
for (R i=-n;i<=a-n+;++i)
{
memset(q1,,sizeof(q1));
h1=h2=;
memset(q2,,sizeof(q2));
t1=t2=;
for (R j=-n;j<=b-n+;++j)
{
ins1(i,j);
ins2(i,j);
if(j<) continue;
maxx[i+n-][j]=q1[h1].val;
minn[i+n-][j]=q2[h2].val;
if(i<) continue;
big=,sma=inf;
for (int k=;k<=n;++k)
big=max(big,maxx[i+k-][j]),sma=min(sma,minn[i+k-][j]);
ans=min(ans,big-sma);
}
}
printf("%d",ans);
return ;
}

[HAOI2007]理想的正方形

--shzr

矩阵dp的更多相关文章

  1. hdu 4975 最大流问题解决队伍和矩阵,利用矩阵dp优化

    //刚開始乱搞. //网络流求解,假设最大流=全部元素的和则有解:利用残留网络推断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环.见上一篇4888 //至少四个点构成的环,另外一种是用 ...

  2. hdu4975 网络流解方程组(网络流+dfs判环或矩阵DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4975 A simple Gaussian elimination problem. Time Limit: 20 ...

  3. Poj 2411 Mondriaan's Dream(压缩矩阵DP)

    一.Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, ...

  4. hdu 4975 最大流解决行列和求矩阵问题,用到矩阵dp优化

    //刚开始乱搞. //网络流求解,如果最大流=所有元素的和则有解:利用残留网络判断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环,见上一篇4888 //至少四个点构成的环,第二种是用矩 ...

  5. lightOJ 1172 Krypton Number System(矩阵+DP)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1172 题意:一个n进制(2<=n<=6)的数字,满足以下条件:(1)至少包 ...

  6. POJ2778&HDU2243&POJ1625(AC自动机+矩阵/DP)

    POJ2778 题意:只有四种字符的字符串(A, C, T and G),有M中字符串不能出现,为长度为n的字符串可以有多少种. 题解:在字符串上有L中状态,所以就有L*A(字符个数)中状态转移.这里 ...

  7. bzoj1009 KMP+矩阵dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=1009 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(<=Xi<=), ...

  8. ZZNU 2182 矩阵dp (矩阵快速幂+递推式 || 杜教BM)

    题目链接:http://47.93.249.116/problem.php?id=2182 题目描述 河神喜欢吃零食,有三种最喜欢的零食,鱼干,猪肉脯,巧克力.他每小时会选择一种吃一包. 不幸的是,医 ...

  9. Luogu3702 SDOI2017 序列计数 矩阵DP

    传送门 不考虑质数的条件,可以考虑到一个很明显的$DP:$设$f_{i,j}$表示选$i$个数,和$mod\ p=j$的方案数,显然是可以矩阵优化$DP$的. 而且转移矩阵是循环矩阵,所以可以只用第一 ...

随机推荐

  1. Visual Studio 命令提示符

    Visual Studio 命令提示和 SDK 命令提示会自动设置环境变量,使您能够轻松使用 .NET Framework 工具. 在 .NET Framework 4 版 和更高版本中,应使用 Vi ...

  2. EPPlus批量插入图片到Excel

    #region 测试EPPlus插入图片        public static void Createsheel2()        {                      WebClien ...

  3. RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列

    一.理论: .net环境下,C#代码调用RabbitMQ消息队列,本文用easynetq开源的.net Rabbitmq api来实现. EasyNetQ 是一个易于使用的RabbitMQ的.Net客 ...

  4. JavaScript之String总汇

    一.常用属性 ·length:返回字符串中字符长度 let str = 'asd '; str.length = 1;//无法手动修改,只读 console.log(str.length);//4 二 ...

  5. 【JVM】1、java虚拟机参数-X 与 -XX的区别

    Options that begin with -X are non-standard (not guaranteed to be supported on all VM implementation ...

  6. java设计模式-----20、模板方法模式

    概念: Template Method模式也叫模板方法模式,是行为模式之一,它把具有特定步骤算法中的某些必要的处理委让给抽象方法,通过子类继承对抽象方法的不同实现改变整个算法的行为. 模板方法模式的应 ...

  7. mongodb与mysql区别(超详细)

    MySQL是关系型数据库. 优势: 在不同的引擎上有不同 的存储方式. 查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高. 开源数据库的份额在不断增加,mysql的份额页在持续增长. 缺 ...

  8. 【读书笔记】iOS-网络-Web Service协议与风格

    协议指的是在与其它系统交换结构化信息时所要遵循的一套格式,过程与规则.此外,协议定义了在传输过程中所要使用的数据格式.这样,接收系统就能正确地解释结构化信息并做出正应的回应. 1,简单对象访问协议. ...

  9. IE9+下如何让input的placeholder样式生效

    :-ms-input-placeholder.el-input__inner { color: #97a8be;}:-ms-input-placeholder.el-textarea__inner{ ...

  10. [基础架构]PeopleSoft Tuxedo 重要文件说明

    我们都知道PeopleSoft是由几个不同的服务组成的,他们在PeopleSoft体系结构中扮演着自己的角色.这些服务具有不同的文件结构并包含重要的可执行文件和配置文件. 以下是Peoplesoft体 ...