• bzoj1177&p3625 [APIO2009]采油区域p[大力讨论]


    我好菜菜啊。

    给定矩形,从中选出三个边长K的正方形互不重叠,使得覆盖到的数总和最大。


    想的时候往dp上钻去了。。结果一开始想了一个错的dp,像这样

     1 /**************************************************************
     2     Problem: 1177
     3     User: stealthassassin
     4     Language: C++
     5     Result: Wrong_Answer
     6 ****************************************************************/
     7  
     8 #include<iostream>
     9 #include<cstdio>
    10 #include<cstring>
    11 #include<cmath>
    12 #include<algorithm>
    13 #define dbg(x) cerr<<#x<<" = "<<x<<endl
    14 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
    15 using namespace std;
    16 typedef long long ll;
    17 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    18 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    19 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    20 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    21 template<typename T>inline T _max(T A,T B,T C){return _max(A,_max(B,C));}
    22 template<typename T>inline T read(T&x){
    23     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    24     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    25 }
    26 const int N=1500+7;
    27 ll sum[N][N];
    28 int f[N][N][3],n,m,A;
    29 inline int get_sum(int xa,int ya,int xb,int yb){return sum[xb][yb]-sum[xa][yb]-sum[xb][ya]+sum[xa][ya];}
    30  
    31 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    32     read(n),read(m),read(A);
    33     for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)sum[i][j]=read(sum[i][j])+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    34     for(register int k=1;k<=3;++k)for(register int i=A;i<=n;++i)for(register int j=A;j<=m;++j)
    35     f[i][j][k]=_max(f[i-1][j][k],f[i][j-1][k],_max(f[i-A][j][k-1],f[i][j-A][k-1])+get_sum(i-A,j-A,i,j));//ddbg(i,j),ddbg(k,f[i][j][k]);
    36     printf("%d
    ",f[n][m][3]);
    37     return 0;
    38 }
    View Code

    结果WA。还发现竟然骗了40pts。很快就发现dp推得有问题。明显没有办法用简单的dp状态来表示,想了一会复杂的dp方法,想不出来,然后就觉得这题DP不可做。然后陷入了僵局,尝试各种乱七八糟的做法却无果。

    之后翻题解才发现,你3个正方形,个数那么少,用不了dp,那明摆着就是让你研究他们相对位置关系嘛。。

    所以下面大力讨论一下,最大答案就有了这几种可能分布情况(红线表示区块的分界):

    所以只要对每种情况都找一下最大总和,具体就是枚举边界线,3456四种分别二重横竖枚举$O(nm)$,每个区块里找最大值矩形,这个可以用前缀和加递推提前预处理,看code。

    12就枚举一条边界线,然后中间那块不妨是k宽度的也没问题,在k宽度中找一个最大的,再配上边上两块最大的。

    所以这题代码真的是写的恶心。。。而且BZOJ数据有锅,用快读还超时。。做了近4小时,心态有点崩溃。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define dbg(x) cerr<<#x<<" = "<<x<<endl
     7 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
     8 #define rep(i,x,y) for(register int i=x;i<=y;++i)
     9 #define per(i,x,y) for(register int i=x;i>=y;--i)
    10 using namespace std;
    11 typedef long long ll;
    12 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    13 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline T _max(T A,T B,T C){return _max(A,_max(B,C));}
    17 //namespace io
    18 //{
    19 //    const int SIZE = (1 << 21) + 1;
    20 //    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
    21 //    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    22 //    inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
    23 //    inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
    24 //    template <class I>
    25 //    inline void read(I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
    26 //        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
    27 //    template <class I>
    28 //    inline void print (I x){
    29 //        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr--]);}
    30 //    struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
    31 //}
    32 //using io::read;
    33 //using io::putc;
    34 //using io::print;
    35 const int N=1500+5;
    36 int a[N][N],zs[N][N],ys[N][N],zx[N][N],yx[N][N],ans;
    37 int n,m,k;
    38 
    39 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
    40     cin>>n>>m>>k;
    41     rep(i,1,n)rep(j,1,m)scanf("%d",&a[i][j]),a[i][j]+=a[i][j-1];
    42     rep(i,1,n)rep(j,1,m)a[i][j]+=a[i-1][j];
    43     per(i,n,k)per(j,m,k)a[i][j]=a[i][j]-a[i-k][j]-a[i][j-k]+a[i-k][j-k];
    44     rep(i,k,n)rep(j,k,m)zs[i][j]=max(a[i][j],max(zs[i-1][j],zs[i][j-1]));
    45     rep(i,k,n)per(j,m,k)ys[i][j]=max(a[i][j],max(ys[i-1][j],ys[i][j+1]));
    46     per(i,n,k)rep(j,k,m)zx[i][j]=max(a[i][j],max(zx[i+1][j],zx[i][j-1]));
    47     per(i,n,k)per(j,m,k)yx[i][j]=max(a[i][j],max(yx[i+1][j],yx[i][j+1]));
    48     rep(i,k,n-2*k)rep(j,k,m)ans=max(ans,zs[i][m]+a[i+k][j]+yx[i+k*2][k]);
    49     rep(i,k,m-2*k)rep(j,k,n)ans=max(ans,zs[n][i]+a[j][i+k]+yx[k][i+k*2]);
    50     rep(i,k,n-k)rep(j,k,m-k)ans=max(ans,zs[i][j]+ys[i][j+k]+yx[i+k][k]);
    51     rep(i,k,n-k)rep(j,k,m-k)ans=max(ans,zx[i+k][j]+yx[i+k][j+k]+zs[i][m]);
    52     rep(i,k,m-k)rep(j,k,n-k)ans=max(ans,zs[j][i]+zx[j+k][i]+yx[k][i+k]);
    53     rep(i,k,m-k)rep(j,k,n-k)ans=max(ans,ys[j][i+k]+yx[j+k][i+k]+zs[n][i]);
    54     printf("%d
    ",ans);
    55     return 0;
    56 }
  • 相关阅读:
    汇编笔记
    PHP笔记——SOAP
    Eclipse 插件资源地址记录
    使用SetWindowLong修改窗口样式
    C++ builder 剪贴板Clipboard使用
    c++ builder 实现右键选择节点实现方式
    c++ builder 使listview获得焦点并选择第一个节点
    c++ builder 2009 启用codeguard 检测内存泄漏
    c++ builder 2009如何生成独立运行exe
    WPF编程学习——样式
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10524980.html
Copyright © 2020-2023  润新知