【BZOJ 2738】 矩阵乘法

2738: 矩阵乘法

Time Limit: 20 Sec Memory Limit: 256 MB

Submit: 841 Solved: 351

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

思路题+整体二分。

首先把矩阵中的元素升序排序,然后就可以整体二分了。

即二分每个询问矩阵是在第几大的元素加的时候达到了k个(用二维树状数组优化)。

【BZOJ 2527】一样了。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define M 500005
using namespace std;
struct jz
{
    int x,y,v;
}a[M];
struct Query
{
    int x1,y1,x2,y2,k,id,cur;
}q[M],b[M];
int t[505][505],ans[M],n,Q;
bool cmp(jz a,jz b)
{
    return a.v<b.v;
}
int lowbit(int x)
{
    return x&(-x);
}
void Update(int x,int y,int k)
{
    if (!x) x++;
    if (!y) y++;
    for (int i=x;i<=n;i+=lowbit(i))
        for (int j=y;j<=n;j+=lowbit(j))
            t[i][j]+=k;
}
int sum(int x,int y)
{
    int ans=0;
    for (int i=x;i>0;i-=lowbit(i))
        for (int j=y;j>0;j-=lowbit(j))
            ans+=t[i][j];
    return ans;
}
int Getsum(int x)
{
    return sum(b[x].x2,b[x].y2)-sum(b[x].x2,b[x].y1-1)-sum(b[x].x1-1,b[x].y2)+sum(b[x].x1-1,b[x].y1-1);
}
void read(int &tmp)
{
    tmp=0;
    char ch=getchar();
    int fu=1;
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())
        if (ch==‘-‘) fu=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())
        tmp=tmp*10+ch-‘0‘;
    tmp*=fu;
}
void Solve(int l,int r,int h,int t)
{
    if (h>t) return;
    if (l==r)
    {
        for (int i=h;i<=t;i++)
            ans[b[i].id]=a[l].v;
        return;
    }
    int mid=(l+r)>>1;
    for (int i=l;i<=mid;i++)
        Update(a[i].x,a[i].y,1);
    int t1=h-1,t2=t+1;
    for (int i=h;i<=t;i++)
    {
        int tmp=Getsum(i);
        if (tmp+b[i].cur>=b[i].k) q[++t1]=b[i];
        else b[i].cur+=tmp,q[--t2]=b[i];
    }
    for (int i=h;i<=t;i++)
        b[i]=q[i];
    for (int i=l;i<=mid;i++)
        Update(a[i].x,a[i].y,-1);
    Solve(l,mid,h,t1);
    Solve(mid+1,r,t2,t);
}
int main()
{
    scanf("%d%d",&n,&Q);
    int now=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            read(a[++now].v),a[now].x=i,a[now].y=j;
    sort(a+1,a+1+now,cmp);
    for (int i=1;i<=Q;i++)
        read(b[i].x1),read(b[i].y1),read(b[i].x2),read(b[i].y2),read(b[i].k),
        b[i].id=i,b[i].cur=0;
    Solve(1,now,1,Q);
    for (int i=1;i<=Q;i++)
        printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-08-28 00:43:03

【BZOJ 2738】 矩阵乘法的相关文章

【CDQ】BZOJ 2738 矩阵乘法

题意:给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数 思路: 整体二分+二维树状数组 二分询问的答案mid,将数值小等mid的全部插入二维树状数组 然后查询每个矩阵内的元素个数,若数量>K-1则放左边,否则放右边 继续向下分治,左边二分l-mid,右边mid-r 代码: #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include

bzoj 2738 矩阵乘法

其实这题跟矩阵乘法没有任何卵关系,直接整体二分,用二维树状数组维护(刚刚学会>_<),复杂度好像有点爆炸(好像有十几亿不知道是不是算错了),但我们不能怂啊23333. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,qq; 7 int map[506][505]; 8 i

BZOJ 2738 矩阵乘法(整体二分+二维树状数组)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2738 [题目大意] 给出一个方格图,询问要求求出矩阵内第k小的元素 [题解] 我们对答案的大小进行整体二分,用二维树状数组维护二维区间和, 将超过数量的分治到左区间,不满足的分治到右区间即可. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std;

BZOJ 2738 矩阵乘法 分块

题目大意:给定一个矩阵,多次求一个子矩阵中的第k小 正解:CDQ分治 不会 二维莫队? 不会 于是果断分块大法好(又是 我们将这n*n个数排序 分n次插入 每次插入n个 每次插入后 去链表上处理尚未出解的询问(我懒得写链表写了并查集) 如果当前询问的子矩阵内已经插入大于等于k个数 那么答案一定在当次插入的n个数中 暴力查找即可 时间复杂度O(n^3+nq) 好卡-- #include<cstdio> #include<cstring> #include<iostream>

BZOJ 2738 矩阵乘法 整体二分+二维树状数组

题目大意:给定一个矩阵,多次求某个子矩阵中的第k小 分块解法见 http://blog.csdn.net/popoqqq/article/details/41356899 <论除最小割外题目解法从来与题目名称无关系列> 整体二分 Solve(x,y,S)表示处理答案在[x,y]区间内的询问集合S 预先将所有数按照大小排序 每次将[1,mid]之间的数插入树状数组 然后对于分治内部的每一个询问 去树状数组中查询相应子矩阵的数值 如果小于等于k就划分到左集合S1 否则划分到右集合S2 然后Solv

bzoj 3240 矩阵乘法+十进制快速幂

首先,构造出从f[][i]->f[][i+1]的转移矩阵a,和从f[i][m]->f[i+1][1]的转移矩阵b, 那么从f[1][1]转移到f[n][m]就是init*(a^(m-1)*b)^(n-1)*(a^(m-1)). 然后用用十进制快速幂(因为输入用的是10进制,这样就避免了高精度除法). 第一次写十进制快速幂,大概的思想是维护当前位是1-9的要乘的矩阵,然后再通过这9个矩阵自己转移. 1 /**********************************************

bzoj2738: 矩阵乘法

2738: 矩阵乘法 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1396  Solved: 603[Submit][Status][Discuss] Description 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. Input 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共N*N个数,表示这个矩阵: 再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角

矩阵乘法专题1——bzoj 1297 [SCOI2009] 迷路题解

题目链接 题意:给两个长度分别为n和m的序列,现在有两种操作:1.分别选择两个序列的一个非空前缀,切两个前缀的最后一位相同,删除之,得到1分(只累计),消耗e:2.直接删除两个序列,消耗值定于两个序列之前删除的元素个数之和,并且使得得到的分有效(之前没有有效分) 分析: 首先,问题其实就是转化成,进行若干次操作1,然后进行操作2 还要找到一个判别标准,来评判较优的状态(贪心) 每次的消耗值比较大,其实可以计算出最大的删除次数,这个值不是很大 状态表示: 简单的,一个状态可以表示为串A的位置.串B

矩阵乘法专题2——bzoj 1706 [usaco2007 Nov] relays 奶牛接力跑 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24960651 [原题] 1706: [usaco2007 Nov]relays 奶牛接力跑 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 340  Solved: 162 [Submit][Status] Description FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目.至于进行接力