3241: [Noi2013]书法家 DP

来源:互联网 发布:startos软件源 编辑:程序博客网 时间:2024/04/28 01:47

《根据数据范围猜做法系列》
首先感受一下题意,像一个DP。。。
然后观察一下数据范围,感觉应该是个三次方的DP。。
然后发现nm小不少,应该是O(n2m)的。。。
然后观察一下图形,发现了非常奇妙的性质。。

可以分成这11部分,然后用fi表示第i块,枚举列进行转移。
大概有以下转移:
empty1,11,12,22,23,33,34,44,45,56,66,67,78,88,89,99,910,1010,1011,1111
然后大力DP就好了。。。

#include<iostream>#include<cstdio>#include<cstring>#define clear(a) memset(a,-63,sizeof(a))using namespace std;const int N=155;const int M=505;int n,m,f4,f8,ans,INF;int a[M][N],s[N];int f1[N][N],f2[N][N],f3[N][N],f5[N][N],f6[N][N],f7[N][N],f9[N][N],f10[N][N],f11[N][N],s1[N][N],s2[N][N];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}int main(){    n=read(); m=read();    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            a[j][n-i+1]=read();    clear(f1); clear(f2); clear(f3); clear(f5); clear(f6); clear(f7); clear(f9); clear(f10); clear(f11); clear(s1); clear(s2);    INF=-f1[0][0]; f4=f8=ans=-INF;    for (int j=1;j<=m;j++)    {        for (int i=1;i<=n;i++) s[i]=s[i-1]+a[j][i];        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                ans=max(ans,f11[l][r]=max(f11[l][r],f10[l][r])+a[j][l]+a[j][r]);        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f10[l][r]=max(f10[l][r],f9[l][r])+s[r]-s[l-1];        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f9[l][r]=max(f9[l][r],f8)+a[j][l]+a[j][r];        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f8=max(f8,f7[l][r]);        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f7[l][r]=f6[l][r]+s[r]-s[l-1];        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f6[l][r]=max(f6[l][r],f5[l][r])+a[j][l]+a[j][r];        for (int l=1;l<=n;l++)            for (int r=l+2;r<=n;r++)                f5[l][r]=f4+s[r]-s[l-1];        for (int l=1;l<=n;l++)            for (int r=l+1;r<=n;r++)                f4=max(f4,f3[l][r]);        for (int l=1;l<=n;l++)        {            int tmp=-INF;            for (int r=l+1;r<=n;r++)                tmp=max(tmp,f2[l][r-1]),f3[l][r]=max(f3[l][r],tmp)+s[r]-s[l-1];        }        for (int r=1;r<=n;r++)        {            int tmp=s2[r+1][r];            for (int l=r;l;l--)                tmp=max(tmp,s2[l][r]),f2[l][r]=max(s1[l-1][r],tmp)+s[r]-s[l-1];        }        for (int l=1;l<=n;l++)            for (int r=l;r<=n;r++)                f1[l][r]=max(0,f1[l][r])+s[r]-s[l-1];        for (int l=1;l<=n;l++)            for (int r=n;r;r--)                s2[l][r]=max(f2[l][r],s2[l][r+1]);        for (int r=1;r<=n;r++)            for (int l=1;l<=n;l++)                s1[l][r]=max(f1[l][r],s1[l-1][r]);    }    cout << ans << endl;    return 0;}
0 0
原创粉丝点击