Codeforces Round #662 (Div. 2) D. Rarity and New Dress

题目链接:D. Rarity and New Dress

昨天集训队一名同学在做这道题,为了给他增加信心,我说这题很简单,随便做做就过了,然后今天看了这道题,一下午没写出代码。。。emmm,只想在这对那位同学说声抱歉。

题意

给你一个n*m的网格,每个点有一个字母代表一种颜色,题目构造了一种图案——正菱形图案,图案内的颜色必须相同,单个字符也算一个正菱形。
问你在网格中符合条件的图案有多少个?

题解

首先我们来分析这道题,正菱形可以分为上三角形和下三角形,我们以格子的每个点为菱形中心,那么它对答案的贡献值为min(上三角层数,下三角层数)。其实三角形层数也是以(i,j)为中心所能扩展的正菱形个数。
上三角层数如何求?
通过分析得知上三角的层数等于该中点到最左边/最右边的数量。

设 l [ i ] [ j ] : 以 ( i , j ) 为 中 心 , 向 左 扩 展 最 多 扩 展 的 个 数 {设l[i][j]:以(i,j)为中心,向左扩展最多扩展的个数} l[i][j]:(i,j)
设 r [ i ] [ j ] : 以 ( i , j ) 为 中 心 , 向 右 扩 展 最 多 扩 展 的 个 数 {设r[i][j]:以(i,j)为中心,向右扩展最多扩展的个数} r[i][j]:(i,j)
设 m i d [ i ] [ j ] : 以 ( i , j ) 为 中 心 所 能 组 成 最 大 的 三 角 形 层 数 , 也 是 向 左 / 右 扩 展 的 个 数 {设mid[i][j]:以(i,j)为中心所能组成最大的三角形层数,也是向左/右扩展的个数} mid[i][j]:(i,j)/

由上面易知状态转移方程
l [ i ] [ j ] = ( g [ i ] [ j ] = = g [ i ] [ j − 1 ] ) ? l [ i ] [ j − 1 ] + 1 : 1 ; ( g [ i ] [ j ] 为 网 格 颜 色 ) {l[i][j]=(g[i][j]==g[i][j-1]) ? l[i][j-1]+1:1; (g[i][j]为网格颜色)} l[i][j]=(g[i][j]==g[i][j1])?l[i][j1]+1:1;(g[i][j])
r [ i ] [ j ] = ( g [ i ] [ j ] = = g [ i ] [ j + 1 ] ) ? r [ i ] [ j + 1 ] + 1 : 1 ; ( g [ i ] [ j ] 为 网 格 颜 色 ) {r[i][j]=(g[i][j]==g[i][j+1]) ? r[i][j+1]+1:1; (g[i][j]为网格颜色)} r[i][j]=(g[i][j]==g[i][j+1])?r[i][j+1]+1:1;(g[i][j])
m i d [ i ] [ j ] = m i n ( l [ i ] [ j ] , r [ i ] [ j ] ) ; {mid[i][j]=min(l[i][j],r[i][j]);} mid[i][j]=min(l[i][j],r[i][j]);

知道了这些上三角数就很好求
设 u p [ i ] [ j ] : 以 ( i , j ) 为 上 三 角 中 心 的 最 大 层 数 {设up[i][j]:以(i,j)为上三角中心的最大层数} up[i][j]:(i,j)

上三角的状态转移方程为:
u p [ i ] [ j ] = ( g [ i ] [ j ] = = g [ i − 1 ] [ j ] ) ? m i n ( m i d [ i ] [ j ] , u p [ i − 1 ] [ j ] + 1 ) : 1 ; {up[i][j]=(g[i][j]==g[i-1][j])?min(mid[i][j],up[i-1][j]+1):1 ;} up[i][j]=(g[i][j]==g[i1][j])?min(mid[i][j],up[i1][j]+1):1;

同理下三角的状态转移方程为:
d o w n [ i ] [ j ] = ( g [ i ] [ j ] = = g [ i + 1 ] [ j ] ) ? m i n ( m i d [ i ] [ j ] , d o w n [ i + 1 ] [ j ] + 1 ) : 1 ; {down[i][j]=(g[i][j]==g[i+1][j])?min(mid[i][j],down[i+1][j]+1):1 ;} down[i][j]=(g[i][j]==g[i+1][j])?min(mid[i][j],down[i+1][j]+1):1;

最终答案就是枚举每个点加上每个点的贡献值: m i n ( u p [ i ] [ j ] , d o w n [ i ] [ j ] ) {min(up[i][j],down[i][j])} min(up[i][j],down[i][j])

代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2005;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

char g[maxn][maxn];
int l[maxn][maxn],r[maxn][maxn],up[maxn][maxn],down[maxn][maxn];
int mid[maxn][maxn];

int main()
{
	ios;
	int n,m;
	cin >> n >> m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) cin >> g[i][j];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(g[i][j]==g[i][j-1]) l[i][j]=l[i][j-1]+1;
			else l[i][j]=1;
		}
		for(int j=m;j>=1;j--)
		{
			if(g[i][j]==g[i][j+1]) r[i][j]=r[i][j+1]+1;
			else r[i][j]=1;
			mid[i][j]=min(l[i][j],r[i][j]);
		}
	}
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=n;i++)
		{
			if(g[i][j]==g[i-1][j]) up[i][j]=min(mid[i][j],up[i-1][j]+1);
			else up[i][j]=1;
		}
		for(int i=n;i>=1;i--)
		{
			if(g[i][j]==g[i+1][j]) down[i][j]=min(mid[i][j],down[i+1][j]+1);
			else down[i][j]=1;
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) ans+=min(up[i][j],down[i][j]);
	cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值