http://acm.hdu.edu.cn/showproblem.php?pid=1559
汉语题,呵呵。
思路:这个题跟我上一篇博文中的那个题的区别就在限制了子矩阵的大小。如果没有看过我上一篇博文的可以先去扫一眼,我们不妨回顾一下,那个题是怎么做的:我们采用了大家都比较熟知的,我自己习惯叫行压缩,我们新建了一个数组link来存放到当前行为止每一列的的和,这样就差不多回到一维的样子。那这个题又该怎么想呢?我们是不是可以采取每行的一部分,使得先满足子矩阵Y的要求,然后在限制列,使得满足子矩阵X的要求,是否可以呢?应该是可以的,但是当时我还有一点没有想通,我要怎么来限制X呢?这题最终解决是我在做完窗口移动那个题之后才想到这题X的限制完全可以用单调队列或者是双端队列来搞定。窗口移动那题,我会在我之后单调队列小结的博文中提到,希望大家关注我博客。
下面是代码:
View Code
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> #include <vector> #include <stack> using namespace std; const int maxn=1500; int m,n,x,y,ma; int num[maxn][maxn],link[maxn]; deque<int>d; void data_in() { scanf("%d %d %d %d",&m,&n,&x,&y); for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) scanf("%d",&num[i][j]); } } inline int max(int x,int y) { return x<y?y:x; } void cal() { int ans=0,width=0; d.clear(); for(int i=1;i<=n;i++) { ans+=link[i]; width++; d.push_back(i); if(width==y) { ma=max(ma,ans); width--; ans-=link[d.front()]; d.pop_front(); // printf("%d\n",link[d.front()]); } } } void solve() { ma=0; for(int i=1;i<=m-x+1;i++) { memset(link,0,sizeof(link)); for(int j=i;j<i+x;j++) { for(int k=1;k<=n;k++) link[k]+=num[j][k]; } cal(); } printf("%d\n",ma); } int main() { int t; scanf("%d",&t); while(t--) { data_in(); solve(); } return 0; }
我代码中是先限制了X,才去用双端队列限制Y。跟之前思路有点出入,但是都无所谓,都可以做。
善待每一天,努力做好自己。
欢迎转载,注明出处。