您的位置:首页 > 其它

[51Nod1487]占领资源

2018-01-10 18:55 106 查看

题目大意:
​  有一个$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))$。

#include<set>
#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
register bool neg=false;
while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return neg?-x:x;
}
inline int getblock() {
register char ch;
while(!isdigit(ch=getchar()));
return ch^'0';
}
typedef std::pair<int,int> Point;
const int N=100,K=10,logN2=15;
std::set<Point> set;
bool vis[N*N],b

;
int n,m,k,a

,dx[K],dy[K],max[N*N][logN2],q[K*K+3];
inline bool check(const int &x,const int &y) {
return x>=0&&x<n&&y>=0&&y<m;
}
inline int id(const int &x,const int &y) {
return x*m+y;
}
inline int log2(const float &x) {
return ((unsigned&)x>>23&255)-127;
}
inline int query(const int &l,const int &r) {
const int k=log2(r-l+1);
return std::max(max[l][k],max[r-(1<<k)+1][k]);
}
inline int calc(const int &x1,const int &y1) {
int ret=q[0]=0;
for(register int i=0;i<k;i++) {
const int x3=x1+dx[i],y3=y1+dy[i];
if(!check(x3,y3)) continue;
b[x3][y3]=true;
for(register int j=0;j<k;j++) {
const int x2=x3-dx[j],y2=y3-dy[j];
if(!check(x2,y2)||vis[id(x2,y2)]) continue;
vis[q[++q[0]]=id(x2,y2)]=true;
}
}
for(register int i=1;i<=q[0];i++) {
vis[q[i]]=false;
}
q[++q[0]]=-1;
q[++q[0]]=n*m;
std::sort(&q[1],&q[q[0]+1]);
for(register int i=1;i<q[0];i++) {
if(q[i]+1<=q[i+1]-1) {
ret=std::max(ret,query(q[i]+1,q[i+1]-1));
}
}
for(register int i=2;i<q[0];i++) {
const int x2=q[i]/m,y2=q[i]%m;
int tmp=0;
for(register int i=0;i<k;i++) {
const int x3=x2+dx[i],y3=y2+dy[i];
if(!check(x3,y3)||b[x3][y3]) continue;
tmp+=a[x3][y3];
}
ret=std::max(ret,tmp);
}
for(register int i=0;i<k;i++) {
const int x3=x1+dx[i],y3=y1+dy[i];
if(!check(x3,y3)) continue;
b[x3][y3]=false;
}
return ret;
}
int main() {
for(register int T=getint();T;T--) {
n=getint(),m=getint(),k=getint();
for(register int i=0;i<n;i++) {
for(register int j=0;j<m;j++) {
a[i][j]=getblock();
}
}
for(register int i=0;i<k;i++) {
dx[i]=getint(),dy[i]=getint();
if(set.count((Point){dx[i],dy[i]})) {
i--,k--;
} else {
set.insert((Point){dx[i],dy[i]});
}
}
set.clear();
for(register int x=0;x<n;x++) {
for(register int y=0;y<m;y++) {
for(register int i=max[id(x,y)][0]=0;i<k;i++) {
if(!check(x+dx[i],y+dy[i])) continue;
max[id(x,y)][0]+=a[x+dx[i]][y+dy[i]];
}
}
}
for(register int j=1;j<=log2(n*m);j++) {
for(register int i=0;j<=log2(n*m-i);i++) {
max[i][j]=std::max(max[i][j-1],max[i+(1<<(j-1))][j-1]);
}
}
int ans=0;
for(register int x1=0;x1<n;x1++) {
for(register int y1=0;y1<m;y1++) {
ans=std::max(ans,max[id(x1,y1)][0]+calc(x1,y1));
}
}
printf("%d\n",ans);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: