zoukankan      html  css  js  c++  java
  • BZOJ5103 : [POI2018]Róznorodno

    从上到下枚举上下底边,那么涉及两行的添加和删除。

    首先预处理出对于每一列,每个位置添加和删除时,是否会对往下$k$个里出现这个颜色造成影响。

    然后对于每种颜色维护一个长度为$m$的bitset,表示哪些列出现过该颜色。

    那么每次修改时,找到前驱和后继,对这一行答案的影响是一段区间加,差分前缀和即可。

    时间复杂度$O(frac{nm^2}{64})$。

    #include<cstdio>
    typedef unsigned int U;
    const int N=3010,M=100010,BUF=72000000;
    char Buf[BUF],*buf=Buf;
    int n,m,K,lim,i,j,k,u,d,a[N][N],cnt[M],s[N],mx;long long ans;bool in[N][N],ou[N][N];
    U f[M][N/32+5];
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    inline int max(int a,int b){return a>b?a:b;}
    inline int min(int a,int b){return a<b?a:b;}
    inline void add(U*f,int x){
      int y=x>>5,pre=-1,suf=-1;
      if(f[y]){
        int o=x&31;U z=f[y];
        for(int i=o-1;~i;i--)if(z>>i&1){pre=y<<5|i;break;}
        for(int i=o+1;i<32;i++)if(z>>i&1){suf=y<<5|i;break;}
      }
      if(pre<0)for(int i=y-1;~i;i--)if(f[i]){pre=i<<5|(31-__builtin_clz(f[i]));break;}
      if(suf<0)for(int i=y+1;i<=lim;i++)if(f[i]){suf=i<<5|__builtin_ctz(f[i]);break;}
      int l=max(pre+1,x-K+1),r=min(x,suf-K);
      if(l<=r)s[l]++,s[r+1]--;
      f[y]^=1U<<(x&31);
    }
    inline void del(U*f,int x){
      int y=x>>5,pre=-1,suf=-1;
      f[y]^=1U<<(x&31);
      if(f[y]){
        int o=x&31;U z=f[y];
        for(int i=o-1;~i;i--)if(z>>i&1){pre=y<<5|i;break;}
        for(int i=o+1;i<32;i++)if(z>>i&1){suf=y<<5|i;break;}
      }
      if(pre<0)for(int i=y-1;~i;i--)if(f[i]){pre=i<<5|(31-__builtin_clz(f[i]));break;}
      if(suf<0)for(int i=y+1;i<=lim;i++)if(f[i]){suf=i<<5|__builtin_ctz(f[i]);break;}
      int l=max(pre+1,x-K+1),r=min(x,suf-K);
      if(l<=r)s[l]--,s[r+1]++;
    }
    int main(){
      fread(Buf,1,BUF,stdin);read(n),read(m),read(K);
      for(i=1;i<=n;i++)for(j=1;j<=m;j++)read(a[i][j]);
      for(j=1;j<=m;j++){
        for(d=1;d<K;d++)if(!(cnt[a[d][j]]++))in[d][j]=1;
        for(u=0;d<=n;u++,d++){
          if(u)if(!(--cnt[a[u][j]]))ou[u][j]=1;
          if(!(cnt[a[d][j]]++))in[d][j]=1;
        }
        for(i=1;i<=n;i++)cnt[a[i][j]]=0;
      }
      lim=(m+1)>>5;
      for(i=1;i<M;i++){
        f[i][0]=1;
        f[i][(m+1)>>5]|=1U<<((m+1)&31);
      }
      for(d=1;d<K;d++)for(j=1;j<=m;j++)if(in[d][j])add(f[a[d][j]],j);
      for(u=0;d<=n;u++,d++){
        if(u)for(j=1;j<=m;j++)if(ou[u][j])del(f[a[u][j]],j);
        for(j=1;j<=m;j++)if(in[d][j])add(f[a[d][j]],j);
        for(j=1,k=0;j+K-1<=m;j++){
          k+=s[j];
          if(k>mx)mx=k;
          ans+=k;
        }
      }
      return printf("%d %lld",mx,ans),0;
    }
    

      

  • 相关阅读:
    pinfinder
    华为方舟编译器
    SSH安全加固
    KindEditor
    SQL SERVER 常见SQL和函数使用
    SQL 时间处理
    sqlSQL2008如何创建定时作业(代理服务)(转)
    登录之问题总结
    文件操作(增删查改)
    SQL2008安装后激活方式以及提示评估期已过解决方法(转)
  • 原文地址:https://www.cnblogs.com/clrs97/p/7946858.html
Copyright © 2011-2022 走看看