zoukankan      html  css  js  c++  java
  • bzoj5103: [POI2018]Ró?norodno

    Description

    给定一个n行m列的矩阵,请对于每个长宽均为k的连续子正方形,统计里面出现过的数值的种类数。

    Input

    第一行包含三个正整数n,m,k(n,m<=3000,k<=min(n,m))。
    接下来n行,每行m个正整数a[i][j](1<=a[i][j]<=100000),表示矩阵中每个位置的数值。

    Output

    输出一行两个整数M和S。
    设f(i,j)表示以(i,j)为左上角的正方形内出现过的数值的种类数,则M表示f的最大值,S表示f的总和。

    对每种颜色分别算贡献,一个点对一个边长k的正方形内每个位置贡献1,但同色贡献只算一次,这是一个正方形求并问题。考虑扫描线,由于边长固定,每个正方形进入和离开扫描线时,至多改变扫描线一个区间的状态,求这个区间的端点,则需要在扫描线上查前趋后继,可以用线段树维护。

    #include<bits/stdc++.h>
    typedef unsigned int u32;
    const u32 A=-1;
    const int N=1e5+7,M=3007;
    char ib[M*M*8],*ip=ib;
    inline int _(){
        int x=0;
        while(*ip<48)++ip;
        while(*ip>47)x=x*10+*ip++-48;
        return x;
    }
    u32 bs[M][2][M/32+2],t0[N][4],t1[N][M/32+2];
    int n,m,k,mx,a[M][M],s[M][M],pv[N];
    long long sum;
    inline void _xor(u32*a,int x){a[x>>5]^=1<<x;}
    inline int _get(u32*a,int x){return a[x>>5]>>x&1;}
    inline int max(int a,int b){return a>b?a:b;}
    inline int min(int a,int b){return a<b?a:b;}
    #define ctz(x) __builtin_ctz(x)
    #define clz(x) (31^__builtin_clz(x))
    inline void cal(int x,int y,int w,int sgn){
        int L=-10000,R=10000,p1=y>>5,p2=y>>10,p3;
        u32 v;
        v=t1[w][p1]&A<<y;
        if(v)R=p1<<5|ctz(v);
        else{
            v=t0[w][p2]&A<<p1<<1;
            if(v){
                p3=p2<<5|ctz(v);
                R=p3<<5|ctz(t1[w][p3]);
            }else for(int i=p2+1;i<3;++i)if(t0[w][i]){
                p3=i<<5|ctz(t0[w][i]);
                R=p3<<5|ctz(t1[w][p3]);
                break;
            }
        }
        v=t1[w][p1]&A>>(31^y);
        if(v)L=p1<<5|clz(v);
        else{
            v=t0[w][p2]&A>>(31^p1)>>1;
            if(v){
                p3=p2<<5|clz(v);
                L=p3<<5|clz(t1[w][p3]);
            }else for(int i=p2-1;i>=0;--i)if(t0[w][i]){
                p3=i<<5|clz(t0[w][i]);
                L=p3<<5|clz(t1[w][p3]);
                break;
            }
        }
        
        L=max(y,L+k);
        R=min(min(m+1,y+k),R);
        if(L<R)s[x][L]+=sgn,s[x][R]-=sgn;
    }
    inline void del(int x,int y,int w){
        _xor(t1[w],y);
        if(!t1[w][y>>5])_xor(t0[w],y>>5);
        cal(x,y,w,-1);
    }
    inline void ins(int x,int y,int w){
        cal(x,y,w,1);
        if(!t1[w][y>>5])_xor(t0[w],y>>5);
        _xor(t1[w],y);
    }
    int main(){
        fread(ib,1,sizeof(ib),stdin);
        n=_();m=_();k=_();
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                a[i][j]=_();
            }
        }
        for(int j=1;j<=m;++j){
            for(int i=1;i<=n;++i){
                int x=a[i][j],&y=pv[x];
                if(y&&y>i-k)_xor(bs[y][0],j),_xor(bs[i][1],j);
                y=i;
            }
            for(int i=1;i<=n;++i)pv[a[i][j]]=0;
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(i>k&&!_get(bs[i-k][0],j))del(i,j,a[i-k][j]);
                if(!_get(bs[i][1],j))ins(i,j,a[i][j]);
            }
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j)s[i][j]+=s[i][j-1];
            for(int j=1;j<=m;++j)s[i][j]+=s[i-1][j];
            if(i>=k)for(int j=k;j<=m;++j){
                sum+=s[i][j];
                if(s[i][j]>mx)mx=s[i][j];
            }
        }
        printf("%d %lld
    ",mx,sum);
        return 0;
    }
  • 相关阅读:
    当Table中td内容为空时,让它显示边框的办法
    超链接可以是JS代码
    学习Filter
    关于SQL语句的拼接问题
    复习JSP时遇到的几个问题
    凡是项目中的增删改都要加事务
    Xshell和SecureCRT连不上VMware虚拟机linux系统
    IBM AIX定义数组变量
    Python模块之re 正则表达式
    Python模块之itertools 用于创建和使用迭代器的函数工具
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7907007.html
Copyright © 2011-2022 走看看