链接

题意:

有个人想要卖国旗

一面国旗可以抽象为一个Codeforces Round #567 (Div. 2) C. Flag (计数DP)_Codeforces的矩形,每一个位置有一个颜色。这个矩形由自上而下三条横向的颜色带组成,每一条颜色带宽度相等,而且相邻两个颜色带颜色不能相同。

现在你有一个Codeforces Round #567 (Div. 2) C. Flag (计数DP)_Codeforces的矩形,你需要计算其中能够称为国旗的子矩形数量。

分析:

首先这样分析:类似一个这样的问题:找出长度为n的字串数量:
如果原长度为5串为Codeforces Round #567 (Div. 2) C. Flag (计数DP)_后缀_03

我们选出先选出a长度为1总方案数+1然后加入b长度为2 总方案数+2(b,ab)然后加入c长度为3总方案数+3(c,bc,abc)一次类推,我们能发现出他就是连续方案数的和。其实就是一个(n+1)n/2的变式

那么我们这样看每次我们需要找到三种颜色,我们用x,y,z代表三种颜色,首先x和y一定不能一样,y和z一定不能一样,x和z可以一样,然后我们看x的高度,他的高度一定与y的高度相等,z的高度只要大于x的高度即可,因为我们可以选取高度为x的高度。这样我们急需要维护一个后缀高度数组,然后判断给出的条件即可,

  • 相邻颜色不能一样,三种颜色高度一致。
ll num[1010][1010];///后缀高度
ll ans, n, m;
char ch[1010][1010];

void solve()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i)
{
scanf("%s", ch[i]+1);
}
/**
* 维护后缀高度
*/
for(int i = n; i >= 1; i--)
{
for(int j = 1; j <= m; j++)
{
if (ch[i][j] == ch[i + 1][j])
{
num[i][j] = num[i + 1][j] + 1;
}
else num[i][j] = 1;
}
}

for (int i = 1; i <= n; i ++)
{
for (int j = 1, k = 0; j <= m; j++)
{
ll hight = num[i][j];///第一种颜色有多高
///不能超过当前n行&&第二种颜色高度一致&&第三种颜色只要大于第一种颜色高度即可&&保证两种相邻颜色不同
if(i + 3 * hight - 1 <= n && num[i + hight][j] == hight && num[i + 2 * hight][j] >= hight && ch[i][j] != ch[i + hight ][j] && ch[i + hight ] != ch[i + 2 * hight ])
{
///每次只要符合条件结果方案书就会+1
///以前有宽度&&第一种颜色当前列与前一列颜色相同&&前1列的高度也是h&&同理判断第二种颜色,第三种颜色
if(k && ch[i][j] == ch[i][j - 1] && num[i][j - 1] == hight && ch[i + hight][j] == ch[i + hight][j - 1] && num[i + hight ][j - 1] == hight && ch[i + 2 * hight][j] == ch[i + 2 * hight][j - 1] && num[i + 2 * hight][j - 1] >= hight)
{
k++;
}
else k = 1; ///宽度为1
}
else k = 0;
ans += k;
}
}
printf("%lld\n", ans);
}