codeforces628 E. Zbazi in Zeydabad 选择枚举对象+用顺序减少重复计算+树状数组优化
来源:互联网 发布:知阴三部曲多少钱一盒 编辑:程序博客网 时间:2024/05/29 17:40
问一个n*m的网格中有多少个z
基本想法应该是枚举z,我想的是枚举中间的z,但是好像复杂度太高了,题解的方法是枚举右上角的z,然后预处理出每个点往左最多的和往左下最多的(nm时间)
枚举每个xy,判断以他为右上角的z有多少个,因为对角线可以变短一点,所以要枚举每个对角线上的点,看右边最长能不能到y
至此算法复杂度为o(nmm)
想办法优化,枚举每一个显然不怎么好优化……只有计算对角线上有哪些能到这个y能想办法优化,需要知道这条对角线上有多少点能到y,就是求有多少点加上往右的最大值之后能>y,找到重复计算的部分,同一个对角线上,y+最大值可能很大,但是每次都要算一次,浪费了很多时间,所以要从右边最大的算起,每条对角线上的某个位置,如果以前可以,那么更小的就也可以所以下次就不用再比较,可是这样复杂度依然没有变……需要一个快速求出全部和的方法
就是用树状数组(或者线段树)每次算刚好能到j列的那些,每个对角线保存一个树状数组,就可以利用前面的性质依次计算
好难啊……自己想不出来?
下面是AC代码,初始化的部分有点麻烦了……不过居然AC也是不容易
#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>#include<vector>using namespace std;int zl[3001][3001];int zr[3001][3001];int zd[3001][3001];int bit[6005][3005];int n,m;int gra[3001][3001];struct node{int x;int y; node(int a,int b):x(a),y(b){};};vector<node> value[3005];//加了之后为j的 int sum(int k,int i){int s = 0;while(i > 0){s += bit[k][i];i -= i & -i;}return s;} void add(int j,int i,int x){while(i <= m){bit[j][i] += x;i += i & -i;}}void init(){for(int i = 1; i <= n; i++){//直接加后面一个就行了,我这样写烦了 int tem = 0; for(int j = m; j >= 1; j--){ if (gra[i][j] == 'z'){ tem++; zr[i][j] = tem;}else tem = 0;} } for(int i = 1; i <= n; i++){ int tem = 0; for(int j = 1; j <= m; j++){ if (gra[i][j] == 'z'){ tem++; zl[i][j] = tem;}else tem = 0;}}for(int i = 1; i <= n; i++){int tem = 0;for(int k = 0; i - k >= 1 && 1 + k <= m; k++){if (gra[i - k][1 + k] == 'z'){tem++;zd[i - k][1 + k] = tem;} else tem = 0;}}for(int j = 2; j <= m; j++){int tem = 0;for(int k = 0; (n - k) >= 1 && j + k <= m; k++){if (gra[n - k][j + k] == 'z'){tem++;zd[n - k][j + k] = tem;}else tem = 0;}}for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++) value[j + zr[i][j] - 1].push_back(node(i,j));}int main(){long long ans = 0;memset(bit ,0,sizeof(bit));//清空 scanf("%d %d",&n,&m);getchar();//输入 for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++) scanf("%c",&gra[i][j]);getchar(); }init();for(int j = m; j >= 1; j--){ for(int i = 0; i < value[j].size();i++) add(value[j][i].x + value[j][i].y,value[j][i].y,1);// for(int i = 1; i <= n; i++){ int len = min(zl[i][j],zd[i][j]); ans += (sum(i + j,j) - sum(i + j,j - len)); }}printf("%I64d\n",ans);return 0;}
0 0
- codeforces628 E. Zbazi in Zeydabad 选择枚举对象+用顺序减少重复计算+树状数组优化
- CodeForces 628E Zbazi in Zeydabad(树状数组)
- codeforces 628E Zbazi in Zeydabad(线段树||树状数组优化)
- Educational Codeforces Round 8(E. Zbazi in Zeydabad(树状数组优化))
- Educational Codeforces Round 8(E. Zbazi in Zeydabad(树状数组优化))★ ★
- E. Zbazi in Zeydabad
- Codeforces edu 8 E. Zbazi in Zeydabad 树状数组 处理技巧
- Codeforces 628E:Zbazi in Zeydabad 树状数组的奇妙用法
- Zbazi in Zeydabad CodeForces
- Educational Codeforces Round 8 E. Zbazi in Zeydabad(BIT)
- Educational Codeforces Round 8 E - Zbazi in Zeydabad
- Educational Codeforces Round 8 E. Zbazi in Zeydabad(给你一个n*m矩阵,每个点可能是'.'或者'z',问有多少种Z子型(Z为一个正方形))
- HDOJ4331-枚举技巧,树状数组统计优化
- ARC 075E Meaningful Mean 枚举+树状数组
- 贪心用树状数组优化
- 暑假-树状数组-E - Stars
- Codeforces 276E(树状数组)
- Codeforces 387E 树状数组
- 下载学习二
- C++ STL
- Java使用imageio 读写图像
- 19个MySQL性能优化要点解析
- WIN7管理员账号删除后无法获取管理员权限解决
- codeforces628 E. Zbazi in Zeydabad 选择枚举对象+用顺序减少重复计算+树状数组优化
- 学习ubuntu之wget命令
- 学习ubuntu之文件/文件夹操作命令
- 学习ubuntu之干掉某个被占用的端口
- java web JSP语法详解
- ubuntu 解压命令
- JSP 遍历ResultSet中的数据并转化为表格
- 如何实现两个JSP数据的传输
- HTML常用的标签总结