JZOJ 5410. 【NOIP2017提高A组集训10.22】小型耀斑

18 篇文章 0 订阅
5 篇文章 0 订阅

Description

Uthuso 的核反应失控了,她在地灵殿释放了几颗大核弹.地灵殿可以看做一个大小为n*m 的矩阵.一颗大小为k 的核弹,对于任意一个与爆炸中心曼哈顿距离小于k 的地区,会造成(k-(该地区到爆炸中心曼哈顿距离))*(该地区的价值)的损失.现在,地灵殿方面想统计一下每颗核弹造成的损失,请你来帮忙计算.

Input

从flare.in 中读入数据第一行为两个整数n,m接下来n 行每行m 个整数,代表第i 行第j 个区域的价值接下来一行为一个整数Q,代表核弹的数目.接下来Q 行每行三个整数x,y,k,代表第i 颗核弹的爆炸中心以及它的大小.

Output

输出到文件flare.out 中Q 行,每行1 个整数,代表第i 颗核弹的损失.

Sample Input

5 51 2 3 4 59 8 7 6 52 3 3 3 36 6 6 6 61 4 2 8 55
1 1 15 5 13 3 32 2 24 2 2

Sample Output

1
5
833731

Data Constraint

对于30%的数据,满足n<=300,m<=300,Q<=300对于60%的数据,满足n<=300,m<=300对于100%的数据,满足1<=n<=2000,1<=m<=2000,1<=Q<=200000,1<=k<=min(x,y,n-x+1,m-y+1),1<=每个区域的价值<=1000000

Hint

由于本题输入输出量极大,请使用较快的输入输出方式

Hint

Solution

  • 这题我的方法比较笨,代码打了100年……

  • 这题是预处理和前缀和的终极体现,想出如何通过前缀和来计算答案十分关键。

  • 对于每个核弹,要计算的答案是一个菱形,而且菱形上的点还要乘上系数,怎么办呢?

  • 考虑将每个菱形分割成四个三角形,对于每个三角形分别统计即可。

Solution

  • 对于右上角的三角形(其他同理,这里不做讨论),如上图所示:

  • s[i][j] 表示到第 i 行、第 j 列 的一个锯齿状的价值和(系数全为1),显然有:

    s[i][j]=s[i1][j1]+k=1ja[i][k]

  • 显然我们可以先做一遍前缀和预处理出 a 矩阵的子矩阵和。

  • 再设 h[i][j] 表示有系数的锯齿阵的价值和(系数就是曼哈顿距离),则有:

    h[i][j]=h[i][j1]+s[i][j]

  • 将前一个锯齿阵再覆盖上系数为1的锯齿阵,就能叠起前面的系数。

  • 根据上图,用 h[x][y+k1]h[xk][y1] 就还剩一个楼梯形,还需要减去一个矩阵

  • 于是设 g[i][j] 表示从左下角到 (i,j) 的矩阵和(带系数,还是曼哈顿距离),则有:

    g[i][j]=g[i+1][j]+ (i,j) 1

  • 那个要减的矩阵就等于:

    g[xk+1][y1]g[x+1][y1]k()+ (x,y1) 

  • 这样我们就能统计出一个三角形的价值和了,其他三角形同理。

  • 总时间复杂度为大常数的 O(NM)

Code


#include<cstdio>
using namespace std;
const int N=2002;
long long f[N][N],g[N][N],s[N][N],k[N][N];
long long g1[N][N],s1[N][N],k1[N][N];
long long g2[N][N],s2[N][N],k2[N][N];
long long g3[N][N],s3[N][N],k3[N][N];
inline int read()
{
    int X=0,w=1; char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
int main()
{
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+read();
            s[i][j]=s[i-1][j-1]+f[i][j]-f[i-1][j];
            k[i][j]=k[i][j-1]+s[i][j];
        }
    for(int j=m;j;j--)
        for(int i=1;i<=n;i++)
        {
            s2[i][j]=s2[i-1][j+1]+f[i][j]-f[i][j-1];
            k2[i][j]=k2[i-1][j]+s2[i][j];
        }
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++)
        {
            s3[i][j]=s3[i-1][j-1]+f[i][j]-f[i][j-1];
            k3[i][j]=k3[i-1][j]+s3[i][j];
        }
    for(int i=1;i<=n;i++)
    {
        long long sum=0;
        for(int j=m;j;j--)
        {
            sum+=f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1];
            g3[i][j]=g3[i-1][j]+f[i-1][m]-f[i-1][j-1]+sum;
        }
    }
    for(int i=1;i<=n;i++)
    {
        long long sum=0;
        for(int j=1;j<=m;j++)
        {
            sum+=f[i][j]-f[i-1][j];
            g2[i][j]=g2[i-1][j]+f[i-1][j]+sum;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=m;j;j--)
        {
            s1[i][j]=s1[i-1][j+1]+f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1];
            k1[i][j]=k1[i][j+1]+s1[i][j];
        }
    for(int i=n;i;i--)
    {
        long long sum=0;
        for(int j=1;j<=m;j++)
        {
            sum+=f[i][j]-f[i-1][j];
            g[i][j]=g[i+1][j]+f[n][j]-f[i][j]+sum;
        }
    }
    for(int i=n;i;i--)
    {
        long long sum=0;
        for(int j=m;j;j--)
        {
            sum+=f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1];
            g1[i][j]=g1[i+1][j]+f[n][m]-f[n][j-1]-f[i][m]+f[i][j-1]+sum;
        }
    }
    int q=read();
    while(q--)
    {
        int x=read(),y=read(),K=read();
        long long ans=k[x][y+K-1]-k[x-K][y-1];
        long long sum=g[x-K+1][y-1]-g[x+1][y-1]-(f[n][y-1]-f[x][y-1])*K;
        sum+=f[x][y-1]-f[x-K][y-1];
        ans-=sum;

        ans+=k1[x][y-K+1]-k1[x-K+1][y];
        sum=g1[x-K+2][y]-g1[x+1][y]-(f[n][m]-f[x][m]-f[n][y-1]+f[x][y-1])*(K-1);
        sum+=f[x][m]-f[x-K+1][m]-f[x][y-1]+f[x-K+1][y-1];
        ans-=sum;

        ans+=k2[x+K-1][y]-k2[x][y+K-1];
        sum=g2[x][y+K-2]-g2[x][y-1]-f[x][y-1]*(K-1);
        sum+=f[x][y+K-2]-f[x][y-1];
        ans-=sum;

        ans+=k3[x+K-2][y-1]-k3[x][y-K+1];
        sum=g3[x][y-K+2]-g3[x][y]-(f[x][m]-f[x][y-1])*(K-2);
        sum+=f[x][y-1]-f[x][y-K+1];
        ans-=sum;
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值