Atcoder agc033D

该博客探讨了Atcoder竞赛中agc033D问题的解决方案,指出答案的时间复杂度为O(logn)并具有单调性。博主提出通过动态规划(DP)进行一轮轮处理,定义F[i][j][k]表示(i,j)到(i,k)矩形在T轮内能覆盖的行数,同时引入G[i][j][k]表示(j,i)到(k,i)矩形覆盖的列数,实现了交错更新以简化转移。最终得出的时间复杂度为O(n^3 logn)。" 138188783,8395695,Pytorch实现RDN图像超分:保姆级教程,"['超分辨率重建', '深度学习', 'pytorch', '计算机视觉', '图像处理']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

答案显然是 O ( log ⁡ n ) \mathcal O(\log n) O(logn)级别的,并且有很强的单调性。
考虑一轮轮的做,设 F [ i ] [ j ] [ k ] F[i][j][k] F[i][j][k]表示左上角为 ( i , j ) (i,j) (i,j),右上角为 ( i , k ) (i,k) (i,k)的矩形,用不超过 T T T轮最多覆盖多少行。
T T T推到 T + 1 T+1 T+1的时候有两种转移,一种容易处理,另一种网上很多题解说要二分,其实可以再设 G [ i ] [ j ] [ k ] G[i][j][k] G[i][j][k]表示左上角为 ( j , i ) (j,i) (j,i),左下角为 ( k , i ) (k,i) (k,i)的矩形,用不超过 T T T轮最多覆盖多少列,这样DP的时候可以交错更新。
时间复杂度 O ( n 3 log ⁡ n ) \mathcal O(n^3\log n) O(n3logn)

#include <bits/stdc++.h>

using namespace std;

inline void update(int &x,int y) {
  x=max(x,y);
}

char str[205][205];

int row[205][205],col[205][205];
int f[205][205][205],g[205][205][205];

void pre(int n,int m) {
  for(int i=1;i<=n;i++)
  	for(int j=m;j>0;j--) row[i][j]=((str[i][j]==str[i][j+1])?row[i][j+1]:0)+1;
  for(int i=1;i<=m;i++)
    for(int j=n;j>0;j--) col[j][i]=((str[j+1][i]==str[j][i])?col[j+1][i]:0)+1;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
    	f[i][j][j]=col[i][j];
    	for(int k=j+1;k<=m;k++)
    	  f[i][j][k]=min(f[i][j][k-1],(str[i][k]==str[i][k-1])?col[i][k]:0);
	}
  for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++) {
    	g[i][j][j]=row[j][i];
    	for(int k=j+1;k<=n;k++)
    	  g[i][j][k]=min(g[i][j][k-1],(str[k][i]==str[k-1][i])?row[k][i]:0);
	}
}

int cur1[205][205][205],cur2[205][205][205];

void dp(int n,int m) {
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      for(int k=j;k<=m;k++) {
	    f[i][j][k]+=f[i+f[i][j][k]][j][k];
	    if (f[i][j][k]) update(cur1[j][i][i+f[i][j][k]-1],k-j+1);
	  }
  for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
      for(int k=j;k<=n;k++) {
	    g[i][j][k]+=g[i+g[i][j][k]][j][k];
	    if (g[i][j][k]) update(cur2[j][i][i+g[i][j][k]-1],k-j+1);
	  }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      for(int k=m;k>=j;k--) update(f[i][j][k],max(f[i][j][k+1],cur2[i][j][k]));
  for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
      for(int k=n;k>=j;k--) update(g[i][j][k],max(g[i][j][k+1],cur1[i][j][k]));
}

int main() {
  int n,m;
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) scanf("%s",str[i]+1);
  pre(n,m);
  int ans=0;
  while (f[1][1][m]<n) {
  	ans++;
  	dp(n,m);
  }
  printf("%d\n",ans);
  return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值