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

来源:互联网 发布:tcpip网络层安全协议 编辑:程序博客网 时间:2024/05/17 05:51

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

#include <cstdio>#include <iostream>#include <algorithm>#include <vector>#include <ctime>#define fi first#define se secondusing 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;}