Atcoder agc033 D - Complexity

190 篇文章 2 订阅
84 篇文章 2 订阅

题面

题意

给出一个矩阵,若一个矩阵中的所有元素都相同,则这个矩阵的代价为0,反之可以将它分成两个子矩阵,代价为两个子矩阵的代价的较大值+1.

做法

因为答案是log级别的,所以可以考虑枚举答案,记 d p [ l ] [ r ] [ i ] dp[l][r][i] dp[l][r][i]从第l行到第r行从第i列开始最多可以向右扩展到哪一列所形成的矩阵的代价为当前答案,若 d p [ 1 ] [ n ] [ 1 ] = m dp[1][n][1]=m dp[1][n][1]=m,则表示当前答案即为整个矩形的代价.
a n s = 0 ans=0 ans=0时的答案很好处理,考虑如何将此时的答案转移到ans+1时的答案.一个矩形有两种拼接方法:
1.两个所在行相同的相邻矩形,直接转移: d p [ l ] [ r ] [ i ] = d p [ l ] [ r ] [ d p [ l ] [ r ] [ i ] ] dp[l][r][i]=dp[l][r][dp[l][r][i]] dp[l][r][i]=dp[l][r][dp[l][r][i]]
2.两个所在列相同的相邻矩形, d p [ l ] [ r ] [ i ] = max ⁡ x = l r − 1 m i n ( d p [ l ] [ x ] [ i ] , d p [ x + 1 ] [ r ] [ i ] ) dp[l][r][i]=\max_{x=l}^{r-1}min(dp[l][x][i],dp[x+1][r][i]) dp[l][r][i]=maxx=lr1min(dp[l][x][i],dp[x+1][r][i]),这个可以通过二分找到最优解.

代码

#include<bits/stdc++.h>
#define N 200
using namespace std;

int m,n,ans,dp[2][N][N][N];
char mm[N][N];
bool now,cur;

inline void Max(int &u,int v){if(v>u) u=v;}
int main()
{
	int i,j,p,q,l,r,mid;
	cin>>m>>n;
	for(i=1;i<=m;i++) scanf("%s",mm[i]+1);
	now=1;
	for(q=1;q<=m;q++)
	{
		for(p=q;p>=1;p--)
		{
			for(i=n;i>=1;i--)
			{
				if(p==q)
				{
					if(i==n) dp[now][p][q][i]=n+1;
					if(mm[p][i]==mm[p][i+1]) dp[now][p][q][i]=dp[now][p][q][i+1];
					else dp[now][p][q][i]=i+1;
				}
				else
				{
					if(mm[q-1][i]==mm[q][i]) dp[now][p][q][i]=min(dp[now][p][q-1][i],dp[now][q][q][i]);
					else dp[now][p][q][i]=i;
				}
			}
		}
	}
	for(ans=0;;ans++)
	{
		if(dp[now][1][m][1]==n+1)
		{
			cout<<ans;
			return 0;
		}
		swap(now,cur);
		for(p=1;p<=m;p++)
		{
			for(q=p;q<=m;q++)
			{
				for(i=1;i<=n;i++)
				{
					if(dp[cur][p][q][i]==n+1) dp[now][p][q][i]=n+1;
					else dp[now][p][q][i]=dp[cur][p][q][dp[cur][p][q][i]];
					for(l=p,r=q;l<r;)
					{
						mid=((l+r)>>1);
						Max(dp[now][p][q][i],min(dp[cur][p][mid][i],dp[cur][mid+1][q][i]));
						if(dp[cur][p][mid][i]>dp[cur][mid+1][q][i]) l=mid+1;
						else r=mid;
					}
				}
			}
		}
	}
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值