【JZOJ5270】【GDOI2018模拟8.14】神奇的矩阵

14 篇文章 0 订阅

Description

这里写图片描述

Data Constraint

这里写图片描述
这里写图片描述

Solution

考场上打了个O(N^3logN)的做法,以为可以水70分,结果出题人非常尽职将其卡至50……
我们考虑若将数从大到小加入,那么每个点的贡献即当前矩形内的点的权值和-该数*矩形内的数的数量。若每个点(i,j)表示一个以(i,j)为左上角的k*k正方形的话,那么当前数(i,j)加入后影响的将会是一个左上角(i-k+1,j-k+1)右下角(i,j)的正方形。我们考虑维护一个二维线段树即可。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=5e2+5,mo=1e4+7;
struct code1{
    ll sum,num,bz,bz1;
}f[maxn*maxn*10];
struct code{
    ll x,y,z;
}b[maxn*maxn];
ll a[maxn][maxn];
ll n,m,p,i,t,j,k,l,x,y,z,ans;
bool cmp(code x,code y){
    return x.z>y.z;
}
void make(ll v,ll l,ll r){
    f[v*2].sum=f[v*2].sum+l*f[v].bz;f[v*2].num+=f[v].bz1*l;
    f[v*2+1].sum=f[v*2+1].sum+r*f[v].bz;f[v*2+1].num+=r*f[v].bz1;
    f[v*2].bz+=f[v].bz;f[v*2+1].bz+=f[v].bz;
    f[v*2].bz1+=f[v].bz1;f[v*2+1].bz1+=f[v].bz1;
    f[v].bz=f[v].bz1=0;
}
void insert(ll lx,ll rx,ll ly,ll ry,ll v,ll x,ll y,ll xx,ll yy){
    if (lx>=x && rx<=y && ly>=xx && ry<=yy){
        t+=f[v].sum;k+=f[v].num;
        f[v].bz+=z;f[v].bz1++;
        f[v].sum+=z*(rx-lx+1)*(ry-ly+1);
        f[v].num+=(rx-lx+1)*(ry-ly+1);
        return;
    }
    if (rx-lx>ry-ly){
        ll mid=(rx+lx)/2;
        if (f[v].bz1) make(v,(mid-lx+1)*(ry-ly+1),(rx-mid)*(ry-ly+1));
        if (lx<=y && mid>=x) insert(lx,mid,ly,ry,v*2,x,y,xx,yy);
        if (mid<y && rx>=x) insert(mid+1,rx,ly,ry,v*2+1,x,y,xx,yy);
        f[v].sum=f[v*2].sum+f[v*2+1].sum;
        f[v].num=f[v*2].num+f[v*2+1].num;
    }else{
        ll mid=(ry+ly)/2;
        if (f[v].bz1) make(v,(mid-ly+1)*(rx-lx+1),(ry-mid)*(rx-lx+1));
        if (ly<=yy && mid>=xx) insert(lx,rx,ly,mid,v*2,x,y,xx,yy);
        if (mid<yy && ry>=xx) insert(lx,rx,mid+1,ry,v*2+1,x,y,xx,yy);
        f[v].sum=f[v*2].sum+f[v*2+1].sum;
        f[v].num=f[v*2].num+f[v*2+1].num;
    }
}
int main(){
    freopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&p);
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            scanf("%lld",&a[i][j]),t++,b[t].x=i,b[t].y=j,b[t].z=a[i][j];
    sort(b+1,b+n*m+1,cmp);
    for (i=1;i<=n*m;i++){
        x=b[i].x;y=b[i].y;z=b[i].z%mo;
        t=0;k=0;
        insert(1,n,1,n,1,max((ll)1,x-p+1),min(x,n-p+1),max((ll)1,y-p+1),min(y,m-p+1));
        ans=(ans+t%mo-k*z%mo+mo)%mo;
    }
    ans=ans*2%mo;
    printf("%lld\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值