zoukankan      html  css  js  c++  java
  • 【bzoj4972】小Q的方格纸 前缀和

    题目描述

    方格纸与草稿纸一样,都是算法竞赛中不可或缺的重要工具。身经百战的小Q自然也会随身带着方格纸。小Q的方格纸有n行m列,一共n*m个方格,从上到下依次标记为第1,2,...,n行,从左到右依次标记为第1,2,...,m列,方便起见,小Q称第i行第j列的方格为(i,j)。小Q在方格纸中填满了数字,每个格子中都恰好有一个整数a_{i,j}。小Q不喜欢手算,因此每当他不想计算时,他就会让你帮忙计算。小Q一共会给出q个询问,每次给定一个方格(x,y)和一个整数k(1<=k<=min(x,y)),你需要回答由(x,y),(x-k+1,y),(x,y-k+1)三个格子构成的三角形边上以及内部的所有格子的a的和。

    输入

    第一行包含6个正整数n,m,q,A,B,C(1<=n,m<=3000,1<=q<=3000000,1<=A,B,C<=1000000)
    其中n,m表示方格纸的尺寸,q表示询问个数。
    为了防止输入数据过大,a和询问将由以下代码生成:
    unsigned int A,B,C;
    inline unsigned int rng61(){
        A ^= A << 16;
        A ^= A >> 5;
        A ^= A << 1;
        unsigned int t = A;
        A = B;
        B = C;
        C ^= t ^ A;
        return C;
    }
    int main(){
        scanf("%d%d%d%u%u%u", &n, &m, &q, &A, &B, &C);
        for(i = 1; i <= n; i++)
            for(j = 1; j <= m; j++)
                a[i][j] = rng61();
        for(i = 1; i <= q; i++){
            x = rng61() % n + 1;
            y = rng61() % m + 1;
            k = rng61() % min(x, y) + 1;
        }
    }

    输出

    为了防止输出数据过大,设f_i表示第i个询问的答案,则你需要输出一行一个整数,即:

    $(sumlimits_{i=1}^q 233^{q-i}*f_i) mod 2^{32}$

    样例输入

    3 4 5 2 3 7

    样例输出

    3350931807


    题解

    前缀和

    考虑答案怎么组成:

    (0,0)

    显然答案(红色区域)等于黑色边框(矩形)面积 - 蓝色边框(大三角形)面积 + 绿色边框(小三角形)面积。

    于是维护两种前缀和:第一种维护一般的矩形区域二维前缀和,第二种维护直角边边长为x,左下角横坐标为y,纵坐标为1的等腰直角三角形的数之和。

    然后乱搞就过了。为了防止n和m弄混,可以令n'=m'=max(n,m)。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 3010
    using namespace std;
    unsigned A , B , C , a[N][N] , sum[N][N] , ste[N][N];
    inline unsigned rng61()
    {
        A ^= A << 16;
        A ^= A >> 5;
        A ^= A << 1;
        unsigned t = A;
        A = B;
        B = C;
        C ^= t ^ A;
        return C;
    }
    int main()
    {
        int n , m , q , i , j , x , y , k;
        unsigned ret , ans = 0;
        scanf("%d%d%d%u%u%u" , &n , &m , &q , &A , &B , &C);
        for(i = 1 ; i <= n ; i ++ )
            for(j = 1 ; j <= m ; j ++ )
                a[i][j] = rng61();
        for(i = 1 ; i <= max(n , m) ; i ++ )
            for(j = 1 ; j <= max(n , m) ; j ++ )
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
        for(i = 1 ; i <= max(n , m) ; i ++ )
            for(j = max(n , m) ; j >= 1 ; j -- )
                ste[i][j] = ste[i - 1][j + 1] + sum[j][i] - sum[j - 1][i];
        while(q -- )
        {
            x = rng61() % n + 1;
            y = rng61() % m + 1;
            k = rng61() % min(x , y) + 1;
            ret = (sum[x][y] - sum[x - k][y]) - (ste[y - 1][x - k + 1] - ste[y > k ? y - k - 1 : 0][x + 1]);
            ans = ans * 233 + ret;
        }
        printf("%u
    " , ans);
        return 0;
    }
    
  • 相关阅读:
    SpringCloud Alibaba微服务实战十
    万字长文!分布式锁的实现全都在这里了
    python编程中的小技巧(持续更新)
    工作十年的数据分析师被炒,没有方向,你根本躲不过中年危机
    github入门操作快速上手
    167. 两数之和 II
    167. 两数之和 II
    167. 两数之和 II
    怎么使用Fiddler进行抓包
    怎么使用Fiddler进行抓包
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7413438.html
Copyright © 2011-2022 走看看