• 矩阵乘法 BZOJ 2738


    矩阵乘法

    【问题描述】

    给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。

    【输入格式】

    第一行两个数N,Q,表示矩阵大小和询问组数;
    接下来N行N列一共N*N个数,表示这个矩阵;
    再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。

    【输出格式】

    对于每组询问输出第K小的数。

    【样例输入】

    2 2
    2 1
    3 4
    1 2 1 2 1
    1 1 2 2 3
    【样例输出】

    1
    3

    【样例说明】

    矩阵中数字是109以内的非负整数;
    20%的数据:N<=100,Q<=1000;
    40%的数据:N<=300,Q<=10000;
    60%的数据:N<=400,Q<=30000;
    100%的数据:N<=500,Q<=60000。


    题解:

    将每个点储存下来,排序一下,和询问进行二分

    我们将小于等于当前枚举的答案(即为mid)的点加入树状数组

    对于区间内的询问,查询子矩阵内的小于等于mid的个数,如果大于等于这个询问要求的k,将其放置在左区间,表示第k小在l到mid之间

    否则放置在右区间,表示第k小在mid+1到r之间

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<algorithm>
     7 using namespace std;
     8 inline void Scan(int &x)
     9 {
    10     char c;
    11     while((c = getchar()) < '0' || c > '9');
    12     x = c - '0';
    13     while((c = getchar()) >= '0' && c <= '9')
    14         x = x * 10 + c - '0';
    15 }
    16 const int maxn = 1233;
    17 const int maxq = 300233;
    18 struct dot
    19 {
    20     int x, y, v;
    21 };
    22 dot c[maxq];
    23 struct ask
    24 {
    25     int x, y, a, b, c;
    26 };
    27 ask a[maxq];
    28 int n, q;
    29 int p;
    30 int num;
    31 int ans[maxq];
    32 int id[maxq], tmp[maxq];
    33 bool lr[maxq];
    34 int tr[maxn][maxn];
    35 inline void Ins(int x, int y, int z)
    36 {
    37     for(int i = x; i <= n; i += i & -i)
    38         for(int j = y; j <= n; j += j & -j)
    39             tr[i][j] += z;
    40 }
    41 inline int Ask(int x, int y)
    42 {
    43     int sum = 0;
    44     for(int i = x; i; i -= i & -i)
    45         for(int j = y; j; j -= j & -j)
    46             sum += tr[i][j];
    47     return sum;
    48 }
    49 inline void Two(int x, int y, int l, int r)
    50 {
    51     if(x > y) return;
    52     if(l == r)
    53     {
    54         for(int i = x; i <= y; ++i) ans[id[i]] = r;
    55         return;
    56     }
    57     int mi = l + r >> 1;
    58     while(c[p + 1].v <= mi) ++p, Ins(c[p].x, c[p].y, 1);
    59     while(c[p].v > mi) Ins(c[p].x, c[p].y, -1), --p;
    60     int tot, cnt = 0;
    61     for(int i = x; i <= y; ++i)
    62     {
    63         int k = id[i];
    64         tot = Ask(a[k].a, a[k].b) - Ask(a[k].a, a[k].y - 1) - Ask(a[k].x - 1, a[k].b) + Ask(a[k].x - 1, a[k].y - 1);
    65         if(tot >= a[k].c) lr[i] = true, ++cnt;
    66         else lr[i] = false;
    67     }
    68     int le = x - 1, ri = x + cnt - 1;
    69     for(int i = x; i <= y; ++i)
    70         if(lr[i]) tmp[++le] = id[i];
    71         else tmp[++ri] = id[i];
    72     for(int i = x; i <= y; ++i) id[i] = tmp[i];
    73     Two(x, le, l, mi), Two(le + 1, ri, mi + 1, r);
    74 }
    75 inline bool rule(dot a, dot b)
    76 {
    77     return a.v < b.v;
    78 }
    79 int main()
    80 {
    81     Scan(n), Scan(q);
    82     int val;
    83     for(int i = 1; i <= n; ++i)
    84         for(int j = 1; j <= n; ++j)
    85         {
    86             Scan(val);
    87             c[++num] = (dot) {i, j, val};
    88         }
    89     sort(c + 1, c + 1 + num, rule);
    90     for(int i = 1; i <= q; ++i)
    91         Scan(a[i].x), Scan(a[i].y), Scan(a[i].a), Scan(a[i].b), Scan(a[i].c), id[i] = i;
    92     Two(1, q, 0, c[num].v);
    93     for(int i = 1; i <= q; ++i) printf("%d
    ", ans[i]);
    94 }
  • 相关阅读:
    while语句
    闭包
    文件操作
    Python基础九:高级特性
    Python基础八:函数
    Python基础六:字典和集合
    Python基础七:条件判断和循环结构
    Python基础五:列表和元组
    Python基础四:字符串及编码
    Python基础三:数据类型和变量
  • 原文地址:https://www.cnblogs.com/lytccc/p/6544754.html
Copyright © 2020-2023  润新知