51Nod 1487 思维+线段树
来源:互联网 发布:java数据库连接池写法 编辑:程序博客网 时间:2024/05/22 07:04
题目链接
题意:
有一个
我们可以选择不多于两个格子建立塔,若塔的坐标为
则我们可以收获
同一个格子的价值只能收获一次。
问能获得的最大值。
思路:
才读完感觉像一个DP,但再仔细一想却感觉无从下手。
主要是处理重叠格子的价值只能取一次这个限制。
然后仔细推敲了一下样例,忽然发现,对于塔在点
所以重叠的情况跟
对于当前枚举的点,枚举其能收获的
则
假设当某个点
枚举
最后通过线段树得到区间最大值。
总复杂度:
最后加上最优性剪枝,跑出来时间31ms
代码:
#include<cstdio>#include<cstdlib>#include<cstring>#include<queue>#include<algorithm>using namespace std;#define lson rt<<1#define rson rt<<1|1const int A = 2e4 + 10;const int B = 1e2 + 10;class Seg_Tree{public: int l,r,Mx;}T[A<<2];int N,M,K,maze[B][B],dx[B],dy[B];char s[B];inline void push_up(int rt){ T[rt].Mx = max(T[lson].Mx,T[rson].Mx);}void build_Tree(int rt,int l,int r){ T[rt].l = l,T[rt].r = r; if(l == r){ T[rt].Mx = 0; return; } int mid = (l+r)>>1; build_Tree(lson,l,mid); build_Tree(rson,mid+1,r); push_up(rt);}void update(int rt,int pos,int val){ int l = T[rt].l,r = T[rt].r; if(l == r){ T[rt].Mx += val; return; } int mid = (l+r)>>1; if(pos<=mid) update(lson,pos,val); else update(rson,pos,val); push_up(rt);}bool check(int x,int y){ if(x>=1 && x<=N && y>=1 && y<=M) return true; return false;}int get_sum(int x,int y){ int sum = 0; for(int i=1 ;i<=K ;i++){ if(check(x+dx[i],y+dy[i])) sum += maze[x+dx[i]][y+dy[i]]; } return sum;}void solve(){ for(int x=1 ;x<=N ;x++){ for(int y=1 ;y<=M ;y++){ update(1,x*M+y,get_sum(x,y)); } } int Mx = 0; for(int x=1 ;x<=N ;x++){ for(int y=1 ;y<=M ;y++){ int res = get_sum(x,y); //printf("res = %d",res); if(res + T[1].Mx <= Mx) continue; for(int i=1 ;i<=K ;i++){ int n_x = x + dx[i],n_y = y + dy[i]; if(!check(n_x,n_y)) continue; for(int j=1 ;j<=K ;j++){ if(check(n_x-dx[j],n_y-dy[j])){ update(1,(n_x-dx[j])*M+(n_y-dy[j]),-maze[n_x][n_y]); } } } Mx = max(Mx,res + T[1].Mx); //printf("Mx = %d\n",Mx); for(int i=1 ;i<=K ;i++){ int n_x = x + dx[i],n_y = y + dy[i]; if(!check(n_x,n_y)) continue; for(int j=1 ;j<=K ;j++){ if(check(n_x-dx[j],n_y-dy[j])){ update(1,(n_x-dx[j])*M+(n_y-dy[j]),maze[n_x][n_y]); } } } } } printf("%d\n",Mx);}int main(){ //freopen("input","r",stdin); int T;scanf("%d",&T); while(T--){ scanf("%d%d%d",&N,&M,&K); build_Tree(1,M+1,N*M+M); for(int i=1 ;i<=N ;i++){ scanf("%s",s+1); for(int j=1 ;j<=M ;j++){ maze[i][j] = s[j] - '0'; } } for(int i=1 ;i<=K; i++) scanf("%d%d",&dx[i],&dy[i]); solve(); } return 0;}
阅读全文
0 0
- 51Nod 1487 思维+线段树
- 51nod 1391 01串【线段树,思维】
- 51nod 1091 线段的重叠(贪心思维)
- 51nod 1631 线段树
- 51nod 1364 线段树
- 51nod 1672 线段树
- 51nod 1069【思维】
- 51Nod - 1138 思维
- 51Nod 1335 思维
- 51Nod 1182 思维
- 51nod 1463:找朋友 线段树
- 51NOD 1672 区间交 线段树
- 51nod 1287 加农炮 【线段树】
- 51Nod 1287 加农炮 ( 暴力/线段树
- 51nod 1562 玻璃切割 【线段树】
- 51nod 1461 稳定桌[线段树]
- 51nod 1781 Pinball【DP】【线段树】
- 51Nod-线段相交
- map & hash_map
- 肾8出来了——谈谈你和苹果的故事
- 出栈全排列
- iOS runtime ~ 重要类型
- Android AndroidManifest 清单文件以及权限详解
- 51Nod 1487 思维+线段树
- js学习-对象
- 46.ClassTag 、Manifest、ClassManifest、TypeTag代码实战及其在Spark中的应用源码解析
- HDU1251:统计难题
- Fork函数
- verilogVGA显示字符
- Fails to build with protobuf 2.6.0
- unity学习笔记#3--在unity中读取XML数据
- SDCard读写文件