zoukankan      html  css  js  c++  java
  • 2018牛客网暑期ACM多校训练营(第二场) J

    题目链接:https://www.nowcoder.com/acm/contest/140/J

    时间限制:C/C++ 4秒,其他语言8秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述

    White Rabbit has a rectangular farmland of n*m. In each of the grid there is a kind of plant. The plant in the j-th column of the i-th row belongs the a[i][j]-th type.
    White Cloud wants to help White Rabbit fertilize plants, but the i-th plant can only adapt to the i-th fertilizer. If the j-th fertilizer is applied to the i-th plant (i!=j), the plant will immediately die.
    Now White Cloud plans to apply fertilizers T times. In the i-th plan, White Cloud will use k[i]-th fertilizer to fertilize all the plants in a rectangle [x1[i]...x2[i]][y1[i]...y2[i]].
    White rabbits wants to know how many plants would eventually die if they were to be fertilized according to the expected schedule of White Cloud.

    输入描述:

    The first line of input contains 3 integers n,m,T(n*m<=1000000,T<=1000000)
    For the next n lines, each line contains m integers in range[1,n*m] denoting the type of plant in each grid.
    For the next T lines, the i-th line contains 5 integers x1,y1,x2,y2,k(1<=x1<=x2<=n,1<=y1<=y2<=m,1<=k<=n*m)

    输出描述:

    Print an integer, denoting the number of plants which would die.

    输入

    2 2 2
    1 2
    2 3
    1 1 2 2 2
    2 1 2 1 1

    输出

    3

    题意:

    现有n行m列的矩阵a[1:n][1:m],代表一个农场,

    而a[i][j]等于一个整数k,代表这个位置上的农作物是第 k 种,

    且第 k 种农作物只能施加第 k 种肥料,施加别的种类肥料会使其死亡,

    然后给出T次施肥方案(x1, y1, x2, y2, k),代表对(x1, y1)到(x2, y2)这一块矩阵上所有农作物施加第 k 种肥料,

    现在要求知道这T次施肥方案过后,总共死掉了多少格农作物

    题解:

    先假设我们就用a[i][j]存储了这个格子上的农作物种类,

    使用2D-BIT,不难想到,每次施加第 k 种肥,就给这整个矩阵所有格子全加上k,

    那么最后我们枚举一遍整个矩阵的所有元素,若某一个元素不能整除a[i][j]就是死掉了,

    但是这样一来会出问题,比如第3种农作物上试了一次第1种肥料,又施了一次第2种肥料,那么最后还是能整除3,

    这时候需要用随机数哈希,把每个种类编号映射到一个比较大的随机数(大于本题的种类数最大值1e6),这样就能降低上述问题出现概率到一个可以接受的程度。

    时间复杂度:预处理哈希$Oleft( {nm} ight)$,输入农场$Oleft( {nm} ight)$,T次施肥$Oleft( {T cdot log n cdot log m} ight)$,暴力枚举n*m格子查询是否死亡$Oleft( {nm cdot log n cdot log m} ight)$,在nm≤1e6的情况下,$nm cdot log n cdot log m$不会超过1e8。

    (本题使用的是区间修改、单点查询2D-BIT,模板以及详解请传送门:树状数组进阶

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5;
    
    struct BIT_2D
    {
        int n,m;
        vector<ll> C[maxn];
        int lowbit(int x){return x&(-x);}
        void init(int n,int m) //初始化n行m列矩阵
        {
            this->n=n;
            this->m=m;
            for(int i=1;i<=n;i++)
            {
                C[i].clear();
                for(int j=0;j<=m;j++) C[i].push_back(0);
            }
        }
        void add(int x,int y,ll val)
        {
            for(int i=x;i<=n;i+=lowbit(i))
                for(int j=y;j<=m;j+=lowbit(j)) C[i][j]+=val;
        }
        void range_add(int x1,int y1,int x2,int y2,ll x) //左上角为(x1,y1)右下角为(x2,y2)的矩阵全部加上x
        {
            add(x1,y1,x);
            add(x1,y2+1,-x);
            add(x2+1,y1,-x);
            add(x2+1,y2+1,x);
        }
        ll ask(int x,int y) //查询点(x,y)的值
        {
            ll ret=0;
            for(int i=x;i>0;i-=lowbit(i))
                for(int j=y;j>0;j-=lowbit(j)) ret+=C[i][j];
            return ret;
        }
    }BIT;
    
    int n,m,T;
    vector<ll> a[maxn];
    
    ll has[maxn];
    inline ll get_rand(int m,int n)
    {
        return rand()%(n-m+1)+m;
    }
    void myhash(int m)
    {
        srand(time(NULL));
        for(int i=1;i<=m;i++) has[i]=get_rand(1e6,9e6);
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&T);
        myhash(n*m);
        BIT.init(n,m);
        for(int i=1;i<=n;i++)
        {
            a[i].clear(); a[i].push_back(0);
            for(int j=1,type;j<=m;j++)
            {
                scanf("%d",&type);
                a[i].push_back(has[type]);
            }
        }
        for(int i=1;i<=T;i++)
        {
            int x1,y1,x2,y2,k;
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
            BIT.range_add(x1,y1,x2,y2,has[k]);
        }
    
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(BIT.ask(i,j)%a[i][j] != 0) ans++;
            }
        }
        cout<<ans<<endl;
    }

    注:由于本题n和m给出的范围是n*m≤1e6,显然不能使用1e6*1e6的二维数组,只能用1e6个vector<long long>来代替。

  • 相关阅读:
    json_encode([0])
    try catch throw
    如何 lookback
    协程||进程
    客户错了?
    循环 php 变量会影响到传入的参数
    csv变成xls, csv乱码
    虚拟机不能git push
    数组下标大小写
    php 静态方法
  • 原文地址:https://www.cnblogs.com/dilthey/p/9369236.html
Copyright © 2011-2022 走看看