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

  

时间: 2024-08-01 17:26:40

BZOJ5103 : [POI2018]Róznorodno的相关文章

【BZOJ5101】[POI2018]Pow&#243;d 并查集

[BZOJ5101][POI2018]Powód Description 在地面上有一个水箱,它的俯视图被划分成了n行m列个方格,相邻两个方格之间有一堵厚度可以忽略不计的墙,水箱与外界之间有一堵高度无穷大的墙,因此水不可能漏到外面.已知水箱内每个格子的高度都是[0,H]之间的整数,请统计有多少可能的水位情况.因为答案可能很大,请对10^9+7取模输出.两个情况不同当且仅当存在至少一个方格的水位在两个情况中不同. Input 第一行包含三个正整数n,m,H(n*m<=500000,1<=H<

【BZOJ5099】[POI2018]Pionek 几何+双指针

[BZOJ5099][POI2018]Pionek Description 在无限大的二维平面的原点(0,0)放置着一个棋子.你有n条可用的移动指令,每条指令可以用一个二维整数向量表示.每条指令最多只能执行一次,但你可以随意更改它们的执行顺序.棋子可以重复经过同一个点,两条指令的方向向量也可能相同.你的目标是让棋子最终离原点的欧几里得距离最远,请问这个最远距离是多少? Input 第一行包含一个正整数n(n<=200000),表示指令条数. 接下来n行,每行两个整数x,y(|x|,|y|<=1

【BZOJ5100】[POI2018]Plan metra 构造

[BZOJ5100][POI2018]Plan metra Description 有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度. 已知2到n-1每个点在树上与1和n的距离,请根据这些信息还原出这棵树. Input 第一行包含一个正整数n(2<=n<=500000),表示点数. 第二行包含n-2个正整数d(1,2),d(1,3),...,d(1,n-1),分别表示每个点到1的距离. 第三行包含n-2个正整数d(n,2),d(n,3),...,d(

[POI2018]Pionek

[POI2018]Pionek 题目大意: 在无限大的二维平面的原点放置着一个棋子.你有\(n(n\le2\times10^5)\)条可用的移动指令,每条指令可以用一个二维整数向量表示.请你选取若干条指令,使得经过这些操作后,棋子离原点的距离最大. 思路: 将所有向量极角排序,然后你选取的向量一定是里面连续的一段,由于所有向量排成一个环,所以要复制一遍接在后面,最后用尺取法枚举左右端点即可. 时间复杂度\(\mathcal O(n\log n)\). 源代码: #include<cmath>

【bzoj5102】[POI2018]Prawnicy 堆

题目描述 定义一个区间(l,r)的长度为r-l,空区间的长度为0. 给定数轴上n个区间,请选择其中恰好k个区间,使得交集的长度最大. 输入 第一行包含两个正整数n,k(1<=k<=n<=1000000),表示区间的数量. 接下来n行,每行两个正整数l,r(1<=l<r<=10^9),依次表示每个区间. 输出 第一行输出一个整数,即最大长度. 第二行输出k个正整数,依次表示选择的是输入文件中的第几个区间. 若有多组最优解,输出任意一组. 样例输入 6 3 3 8 4 12

[POI2018]Pow&#243;d?

题目大意: 一个$n\times m(nm\le5\times10^5)$的网格图,每个格子间有一个给定高度的挡板,每个格子的水位是$0\sim h(h\le10^9)$之间的一个整数.问总共有多少种可能的水位情况. 思路: 建立Kruskal重构树,实点代表原图中的格点,虚点代表若干个格点水位越过挡板进行合并后形成的新连通块.求出每个点所代表连通块的水位最大值$max[i]$和最小值$min[i]$,根结点的$max$值为$h$.进行树形DP.转移方程$f[i]=f[ch[i][0]]\tim

[POI2018]Prawnicy

题目大意: 有$n(n\le10^6)$个线段,每个线段覆盖的范围是$[l_i,r_i]$,要求从中选取$k(k\le10^6)$个线段使得这些线段覆盖范围的交集最大,求最大交集及任意一种方案. 思路: 对左端点排序,用堆维护右端点即可. 1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 #include<sys/mman.h> 6 #i

bzoj 5103 [POI2018]R&#243;?norodno??

这个题没有想出来.. 首先显然的一点是我们要对每种颜色做一次不重复的贡献计算. 同种颜色的贡献就是矩形的并.从网上查了资料,矩形面积并用的是扫描线,那么这个我们也可以用扫描线了. 我们考虑枚举横坐标,维护存在于当前横坐标的所有纵坐标的区间.一个性质是所有的矩形都是边长为k的正方形,那么在加入或删除一个区间时只可能影响到一个连续的区间.我们只需要对这个区间操作就行了. 我用的set维护,因为bzoj开O2,所以比其他数据结构要快一些,但是没有bitset快,要跑47s,记得加上fread,这个题的

[武汉加油] bzoj 5099: [POI2018]Pionek 几何+双指针

几何+双指针 题目大意:现在有 \(n\) 个向量,请你选出来一些向量使它们的和的长度最大,输出最大值的平方. 假如我们已经知道了最终向量的方向,我们要想使长度最大,就需要将所有投影在最终向量正方向上的向量都加起来. 所以我们可以按角度枚举最终向量的方向,我们需要加起来的就是一段移动的区间,我们可以用双指针来维护加起来的向量. 因为最终向量的方向有可能是给出的向量,也有可能是向量之间间隔的方向,所以每次移动指针的时候都要更新一下答案. 因为开始给出的向量不一定有序,所以我们需要先将向量排序. #