[51Nod1487]占领资源

题目大意:
​  有一个$n\times m(x,m\leq 100)$的网格图,每个格子有一个权值$w_{i,j}(1\leq w_{i,j}\leq 9)$。你可以在图中选两个格子,每个格子$(x,y)$可以接收$k(k\leq 10)$个格子,$(x+dx[1],y+dy[1]),(x+dx[2],y+dy[2]),\ldots,(x+dx[k],y+dy[k])$的权值。超出边界的能量不接收,每个格子的权值最多被接收一次,问最多能接收多少权值。

思路:
​  考虑选择不同格子,吸收权值的范围不相交的情况,我们可以直接暴力$O(nmk)$求出每个点能吸收的权值,然后选两个最大的加起来即可。
​  现在每个格子的吸收范围可能会相交,因此我们还需要分两种情况考虑。
  我们可以先求出每个点能吸收的权值,然后找出吸收范围会和该点重合的点,不难发现这样的点最多只有$k^2$个。
  对于会相交的点,我们暴力求一下可以吸收哪些点的权值,对于不相交的点,可以直接用稀疏表求区间最大值,时间复杂度$O(nmk^2\log(nm))$。

  1 #include<set>
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<algorithm>
  5 inline int getint() {
  6     register char ch;
  7     register bool neg=false;
  8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return neg?-x:x;
 12 }
 13 inline int getblock() {
 14     register char ch;
 15     while(!isdigit(ch=getchar()));
 16     return ch^'0';
 17 }
 18 typedef std::pair<int,int> Point;
 19 const int N=100,K=10,logN2=15;
 20 std::set<Point> set;
 21 bool vis[N*N],b[N][N];
 22 int n,m,k,a[N][N],dx[K],dy[K],max[N*N][logN2],q[K*K+3];
 23 inline bool check(const int &x,const int &y) {
 24     return x>=0&&x<n&&y>=0&&y<m;
 25 }
 26 inline int id(const int &x,const int &y) {
 27     return x*m+y;
 28 }
 29 inline int log2(const float &x) {
 30     return ((unsigned&)x>>23&255)-127;
 31 }
 32 inline int query(const int &l,const int &r) {
 33     const int k=log2(r-l+1);
 34     return std::max(max[l][k],max[r-(1<<k)+1][k]);
 35 }
 36 inline int calc(const int &x1,const int &y1) {
 37     int ret=q[0]=0;
 38     for(register int i=0;i<k;i++) {
 39         const int x3=x1+dx[i],y3=y1+dy[i];
 40         if(!check(x3,y3)) continue;
 41         b[x3][y3]=true;
 42         for(register int j=0;j<k;j++) {
 43             const int x2=x3-dx[j],y2=y3-dy[j];
 44             if(!check(x2,y2)||vis[id(x2,y2)]) continue;
 45             vis[q[++q[0]]=id(x2,y2)]=true;
 46         }
 47     }
 48     for(register int i=1;i<=q[0];i++) {
 49         vis[q[i]]=false;
 50     }
 51     q[++q[0]]=-1;
 52     q[++q[0]]=n*m;
 53     std::sort(&q[1],&q[q[0]+1]);
 54     for(register int i=1;i<q[0];i++) {
 55         if(q[i]+1<=q[i+1]-1) {
 56             ret=std::max(ret,query(q[i]+1,q[i+1]-1));
 57         }
 58     }
 59     for(register int i=2;i<q[0];i++) {
 60         const int x2=q[i]/m,y2=q[i]%m;
 61         int tmp=0;
 62         for(register int i=0;i<k;i++) {
 63             const int x3=x2+dx[i],y3=y2+dy[i];
 64             if(!check(x3,y3)||b[x3][y3]) continue;
 65             tmp+=a[x3][y3];
 66         }
 67         ret=std::max(ret,tmp);
 68     }
 69     for(register int i=0;i<k;i++) {
 70         const int x3=x1+dx[i],y3=y1+dy[i];
 71         if(!check(x3,y3)) continue;
 72         b[x3][y3]=false;
 73     }
 74     return ret;
 75 }
 76 int main() {
 77     for(register int T=getint();T;T--) {
 78         n=getint(),m=getint(),k=getint();
 79         for(register int i=0;i<n;i++) {
 80             for(register int j=0;j<m;j++) {
 81                 a[i][j]=getblock();
 82             }
 83         }
 84         for(register int i=0;i<k;i++) {
 85             dx[i]=getint(),dy[i]=getint();
 86             if(set.count((Point){dx[i],dy[i]})) {
 87                 i--,k--;
 88             } else {
 89                 set.insert((Point){dx[i],dy[i]});
 90             }
 91         }
 92         set.clear();
 93         for(register int x=0;x<n;x++) {
 94             for(register int y=0;y<m;y++) {
 95                 for(register int i=max[id(x,y)][0]=0;i<k;i++) {
 96                     if(!check(x+dx[i],y+dy[i])) continue;
 97                     max[id(x,y)][0]+=a[x+dx[i]][y+dy[i]];
 98                 }
 99             }
100         }
101         for(register int j=1;j<=log2(n*m);j++) {
102             for(register int i=0;j<=log2(n*m-i);i++) {
103                 max[i][j]=std::max(max[i][j-1],max[i+(1<<(j-1))][j-1]);
104             }
105         }
106         int ans=0;
107         for(register int x1=0;x1<n;x1++) {
108             for(register int y1=0;y1<m;y1++) {
109                 ans=std::max(ans,max[id(x1,y1)][0]+calc(x1,y1));
110             }
111         }
112         printf("%d\n",ans);
113     }
114     return 0;
115 }

 

posted @ 2018-01-10 18:55  skylee03  阅读(141)  评论(0编辑  收藏  举报