[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 }