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\n",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\n",ans);
55     return 0;
56 }

 

posted @ 2019-03-13 18:18  Ametsuji_akiya  阅读(169)  评论(0编辑  收藏  举报