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

Description

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

Solution

这种题我还能说些什么呢….
把它拆成4个三角形,强干啊,900ms压线(自带12常数2333)

Code

#include <cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long  LL;
const int N=2005;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,m1;
int a[N][N],a1[N][N];
int sc[N*100][4][4];
LL Ans[N*100];
LL sum[N][N],b[N][N];
LL sum1[N][N],b1[N][N];
LL c[N][N],c1[N][N];
int CNT(int E)
{
    fo(i,1,n)
    {
        b[i][0]=b[i-1][1];
        b1[i][0]=b1[i-1][1];
        LL t=0,t1=0;
        fo(j,1,m)
        {
            sum[i][j]=(sum[i-1][j]+sum1[i-1][j]+t);
            // while(sum[i][j]>=)sum[i][j]-=;
            b[i][j]=b[i-1][j+1]+t;
            t1+=(LL)a[i][j];
            sum1[i][j]=sum1[i-1][j]+t1;
            b1[i][j]=b1[i-1][j+1]+t1;
            t+=t1;
        }
        b[i][m+1]=b[i][m]+b1[i][m];
        b1[i][m+1]=b1[i][m];
    }
    fod(i,m,1)
    {
        LL t=0,t1=0;
        fo(j,1,n)
        {
            c[j][i]=(c[j-1][i+1]+t);
            // if(c[j][i]>=)c[j][i]-=;
            t1+=a[j][i];
            c1[j][i]=c1[j-1][i+1]+t1;
            t+=t1;
        }
    }
    int q,w,e;
    fo(i,1,m1)
    {
        q=sc[i][E][0],w=sc[i][E][1],e=sc[i][E][2];
        if(e<0||q<1||w<1)continue;
        Ans[i]=(Ans[i]+sum[q][w]-b[q][w-e-1]-b1[q][w-e-1]*(LL)(e+1));
        Ans[i]=(Ans[i]+(sum1[q][w]-b1[q][w-e-1])*(LL)sc[i][E][3]);
        if(q-e-2>0)
        {
            Ans[i]=(Ans[i]+c[q-e-2][w+1]+c1[q-e-2][w+1]*(LL)(e+1));
            Ans[i]=(Ans[i]+(c1[q-e-2][w+1])*(LL)sc[i][E][3]);
        }
    }
}
int main()
{
    freopen("flare.in","r",stdin);
    freopen("flare.out","w",stdout);
    int q,w;
    read(n),read(m);
    fo(i,1,n)fo(j,1,m)a1[i][j]=read(a[i][j]);
    read(m1);
    fo(i,1,m1)
    {
        read(sc[i][0][0]),read(sc[i][0][1]),read(sc[i][0][2]);
        sc[i][0][2]--;sc[i][0][3]=-sc[i][0][2]-1;

        sc[i][1][0]=sc[i][0][0]-1;
        sc[i][1][1]=m-sc[i][0][1];
        sc[i][1][2]=sc[i][0][2]-2;
        sc[i][1][3]=1-sc[i][0][2];

        sc[i][2][0]=n-sc[i][0][0];
        sc[i][2][1]=sc[i][0][1]-1;
        sc[i][2][2]=sc[i][0][2]-2;
        sc[i][2][3]=1-sc[i][0][2];

        sc[i][3][0]=n-sc[i][0][0]+1;
        sc[i][3][1]=m-sc[i][0][1]+1;
        sc[i][3][2]=sc[i][0][2];
        sc[i][3][3]=-sc[i][0][2]-1;
    }
    CNT(0);
    fo(i,1,n)fo(j,1,m)a[i][j]=a1[i][m-j+1];CNT(1);
    fo(i,1,n)fo(j,1,m)a[i][j]=a1[n-i+1][j];CNT(2);
    fo(i,1,n)fo(j,1,m)a[i][j]=a1[n-i+1][m-j+1];CNT(3);
    fo(i,1,m1)printf("%lld\n",((-Ans[i]+(LL)a1[sc[i][0][0]][sc[i][0][1]]*(LL)sc[i][0][3])));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值