今天的第一只dp是带树状数组or线段树优化的最大不下降子段和。
现场在Div2被教做人……
然后现学现卖把longlong炸了就滚粗div2了……
改了一改之后结局还是比较美满的。
第一个DP代码见我的胡言乱语篇……《dp不收flag系列》
然后第二个dp慌乱地做了这样一道题:
给定一个矩阵,有些地方是0,有些地方是1,求一个最大的正方形矩阵使得里面全是1。
那么我们设f[i][j] 表示以(i,j)为右下角的正方形的最大边长,则有f[i][j] = min{f[i - 1][j - 1] + 1 ,up[i][j],left[i][j]};
up和left代表从起点往这个方向走最多能经过几个点,即为最大以这个点为右下角顶点的正方形边长。
代码:
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#define Rep(i,n) for(int i = 1; i <= n ; i ++)
#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)
#define Rep_d(i,n) for(int i = n ; i > 0 ; i --)
#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)
#define RD(i,x,n) for(int i = x; i <= n ; i ++)
#define CLR(a,b) memset(a,b,sizeof(a))
#define v edge[i].to
using namespace std;
const int inf = 1 << 30;
int read(){
char ch = getchar();
while(ch < '0' || ch > '9')ch = getchar ();
int x = 0;
while(ch >= '0' && ch <= '9')x = 10 * x + ch - '0',ch = getchar ();
return x;
}
int f[1005][1005];
bool w[1005][1005];
int up[1005][1005],lft[1005][1005];
int main()
{
int n = read(),m = read();
Rep(i,n)
Rep(j,m){
w[i][j] = read();
if(w[i][j])lft[i][j] = lft[i][j - 1] + 1;
else lft[i][j] = 0;
}
Rep(i,m)
Rep(j,n){
if(w[j][i])up[j][i] = up[j - 1][i] + 1;
else up[j][i] = 0;
}
/* Rep(i,n)
Rep(j,m)
printf("(%d,%d) %d %d\n",i,j,up[i][j],lft[i][j]);*/
CLR(f,127);
f[1][1] = w[1][1];
int ans = 0;
Rep(i,n)
Rep(j,m){
if(w[i][j]){
f[i][j] = min(f[i - 1][j - 1] + 1,min(up[i][j],lft[i][j]));
ans = max(ans,f[i][j]);
}
else f[i][j] = 0;
}
printf("%d\n",ans);
return 0;
}
所以第三道题决定刷个水题:
对于序列A = 『a1 to an』,定义d(A) =(http://pic002.cnblogs.com/images/2012/305173/2012062923105331.png);
求出d(A);也就是最大2个连续字段和。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define CLR(a,b) memset(a,b,sizeof(a))
#define Rep(i,n) for(int i = 1 ; i <= n ; i ++)
#define RepG(i,x) for(int i = head[x]; ~ i ; i = edge[i].next)
#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)
#define Rep_d(i,n) for(int i = n; i >= 1; i --)
#define u t[x]
#define o t[y]
#define lc ch[0]
#define rc ch[1]
#define lson u.lc,l,mid
#define rson u.rc,mid + 1,r
#define N 50005
int l[N],r[N],a[N],n,lMax[N],rMax[N];
int main (){
int cases;
scanf("%d",&cases);
while(cases --){
CLR(lMax,-127),CLR(rMax,-127);
scanf("%d",&n);
Rep(i,n)
scanf("%d",&a[i]);
Rep(i,n)
l[i] = std :: max(l[i - 1] + a[i],a[i]);
Rep_d(i,n)
r[i] = std :: max(r[i + 1] + a[i],a[i]);
Rep(i,n)
lMax[i] = std :: max(lMax[i - 1],l[i]);
Rep_d(i,n)
rMax[i] = std :: max(rMax[i + 1],r[i]);
int Maxn = - (1 << 30);
Rep(i,n)
Maxn = std :: max(Maxn,lMax[i] + rMax[i + 1]);
printf("%d\n",Maxn);
}
return 0;
}
大概就是计算出以x为分界点的左右两边能取得的最大值。