bzoj 2738 矩阵乘法
2017-06-13 17:10
344 查看
2738: 矩阵乘法
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 1529 Solved: 660
[Submit][Status][Discuss]
Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
Input
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
Output
对于每组询问输出第K小的数。
Sample Input
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
Sample Output
1
3
HINT
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
Source
整体二分。
首先把整个矩阵哈希排序,然后做整体二分。
设当前答案为mid,那么将哈希排好序的矩阵中所有val < mid的数字加入bit中,对于每个询问拆成四个容斥一发,统计出来询问范围内 < mid的数字有多少个,即为cnt。如果k > cnt,把询问划分到[mid,r],否则划分到[l,mid-1]。
注意bit的添加与删除设立一个指针now来完成,否则暴力加入删除会TLE。
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 1529 Solved: 660
[Submit][Status][Discuss]
Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
Input
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
Output
对于每组询问输出第K小的数。
Sample Input
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
Sample Output
1
3
HINT
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
Source
【分析】
题目与题干完全没有关系系列。整体二分。
首先把整个矩阵哈希排序,然后做整体二分。
设当前答案为mid,那么将哈希排好序的矩阵中所有val < mid的数字加入bit中,对于每个询问拆成四个容斥一发,统计出来询问范围内 < mid的数字有多少个,即为cnt。如果k > cnt,把询问划分到[mid,r],否则划分到[l,mid-1]。
注意bit的添加与删除设立一个指针now来完成,否则暴力加入删除会TLE。
【代码】
//bzoj 2738 矩阵乘法 #include<bits/stdc++.h> #define ll long long #define p(i,j) ((i-1)*n+(j)) #define M(a) memset(a,0,sizeof a) #define fo(i,j,k) for(i=j;i<=k;i++) using namespace std; const int mxn=505; int n,Q,mx,now; int c[mxn][mxn],ans[60005]; struct node {int x,y,val;} a[250005]; struct query {int id,x1,y1,x2,y2,k;} q[60005],tmp[60005]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x*f; } inline bool comp(node u,node v) { return u.val<v.val; } inline int lowbit(int x) {return x&-x;} inline void add(int x,int y,int v) { for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=n;j+=lowbit(j)) c[i][j]+=v; } inline int getsum(int x,int y) { int sum=0; for(int i=x;i>=1;i-=lowbit(i)) for(int j=y;j>=1;j-=lowbit(j)) sum+=c[i][j]; return sum; } inline void CDQ(int L,int R,int l,int r) { int i,j,l1=L,l2=R,mid=(l+r>>1)+1; if(L>R) return; if(l==r) { fo(i,L,R) ans[q[i].id]=l; return; } while(now<n*n && a[now].val<mid) ++now,add(a[now].x,a[now].y,1); while(now && a[now].val>=mid) add(a[now].x,a[now].y,-1),--now; fo(i,L,R) { int cnt=getsum(q[i].x2,q[i].y2)-getsum(q[i].x2,q[i].y1-1); cnt=cnt-getsum(q[i].x1-1,q[i].y2)+getsum(q[i].x1-1,q[i].y1-1); if(q[i].k>cnt) tmp[l2--]=q[i]; else tmp[l1++]=q[i]; } reverse(tmp+l2+1,tmp+R+1); fo(i,L,R) q[i]=tmp[i]; CDQ(l2+1,R,mid,r),CDQ(L,l1-1,l,mid-1); } int main() { // freopen("rand.txt","r",stdin); int i,j; n=read(),Q=read(); fo(i,1,n) fo(j,1,n) a[p(i,j)]=(node){i,j,read()}; fo(i,1,Q) { q[i].x1=read(),q[i].y1=read(); q[i].x2=read(),q[i].y2=read(); q[i].k=read(),q[i].id=i; } sort(a+1,a+n*n+1,comp); CDQ(1,Q,0,a[n*n].val); fo(i,1,Q) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- 【BZOJ】【2738】&【Tsinsen】【A1333】矩阵乘法
- BZOJ 2738: 矩阵乘法|分块|整体二分
- BZOJ 2738: 矩阵乘法 整体二分 二维树状数组
- BZOJ 2738 矩阵乘法 整体二分+二维树状数组
- 【BZOJ2738】矩阵乘法【整体二分】
- 【bzoj 2738】矩阵乘法(整体二分+树状数组)
- BZOJ_2738_矩阵乘法_整体二分
- [BZOJ 2738] 矩阵乘法 · 分块
- 【BZOJ2738】矩阵乘法(整体二分+二位树状数组)
- [BZOJ2738]矩阵乘法(整体二分)
- 矩阵乘法 BZOJ 2738
- BZOJ 2738 矩阵乘法 整体二分
- 【BZOJ2738】矩阵乘法 [整体二分][树状数组]
- [BZOJ2738]矩阵乘法-二维树状数组-整体二分
- 【国家集训队2012】【BZOJ2738】矩阵乘法
- BZOJ 2738 矩阵乘法 整体二分+二维树状数组
- [BZOJ 2738] 矩阵乘法 【分块】
- 【BZOJ 2738】 矩阵乘法
- 【BZOJ2738】矩阵乘法 整体二分
- bzoj 2738: 矩阵乘法 (整体二分+二维树状数组)