[前缀和 乱搞]BZOJ4972 .小Q的方格纸

发现询问是个等腰直角三角形,那么我们对于每条斜线作为斜边的等腰直角三角形,斜线上处理一下前缀和就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#define fi first
#define se second

using namespace std;

const int N=3005,M=3000010;

typedef unsigned int U;
typedef pair<U,int> ii;

int n,m,q;
U A,B,C;
U x,a[N][N],b[N][N],d[N][N],e[N][N];

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;
}

inline U Pow(U x,int y){
    U ret=1;
    for(;y;y>>=1,x=x*x) if(y&1) ret*=x;
    return ret;
}

int main(){
    scanf("%d%d%d%u%u%u",&n,&m,&q,&A,&B,&C);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=x=rng61(),b[i][j]=b[i-1][j]+x,d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+x;
    U ret=0;
    for(int i=1;i<=n;i++){
        int x=i,y=1; U p=0;
        for(int j=1;x && y<=m;j++){
            p+=b[i][j]-b[x-1][j];
            e[x][y]=p;
            x--; y++;
        }
    }
    //printf("%d\n",clock());
    for(int i=2;i<=m;i++){
        int x=n,y=i; U p=0;
        for(int j=1;x && y<=m;j++){
            p+=b[n][y]-b[x-1][y];
            e[x][y]=p;
            x--; y++;
        }
    }
    U g=Pow(233,q-1),inv=Pow(233,2147483647);
    for(int i=1;i<=q;i++){
        int x=rng61()%n+1,y=rng61()%m+1,k=rng61()%min(x,y)+1;
        //cout<<x<<' '<<y<<' '<<k<<endl;
        U cur=e[x-k+1][y];
        if(y-k>=1){
            cur+=-e[x+1][y-k]-(d[x-k+1+min(n-x+k-1,y-1)][y]-d[x-k+1+min(n-x+k-1,y-1)][y-k]-d[x][y]+d[x][y-k]);
        }
        ret+=g*cur;
        /*cout<<x-k+1+min(n-x+k-1,y-1)<<' '<<y<<endl;
        cout<<x-k+1+min(n-x+k-1,y-1)<<' '<<y-k<<endl;
        cout<<x<<' '<<y<<endl;
        cout<<x<<' '<<y-k<<endl;*/
        //c[x+1][y-k].push_back(ii(-(long long)g,y));
        //c[x-k+1][y].push_back(ii(g,y));
        g*=inv;
    }
    cout<<ret<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值