题解:CF1393D Rarity and New Dress
观察发现题解区都是大佬,写的题解十分简略,对萌新十分不友好,于是本蒟蒻来写一篇超详细的题解。
思路
显然求出以每个点为最下端点的最大大小菱形的大小
f_{i,j} ,然后答案就是:\sum_{i = 1}^n \sum_{j = 1}^m f_{i,j} 但是显然
f_{i,j} 是不能直接求的,就算使用二分加矩阵转置加预处理也只能做到最坏\mathcal{O}(nm \sqrt{nm} \log \sqrt{nm}) 。显然是不足以通过的。
所以肯定得进行一些小小的转化。
对于一个菱形,假设最下端点是
比较显然的一点是,大菱形一定是由小菱形推出的,所以不妨大胆尝试推一下。
设
那么根据刚刚对于菱形的分析可以得到:
于是可得:
于是我们想要判断
但是这是一件很麻烦的事情,麻烦在四个格子上。
由于本身
其中
up_{i,j} 表示(i,j) 往上只看第j 列的连续同色格子数。
于是我们就可以列状态转移方程了:
显然,这等价于:
直接转移就行了,时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N = 2005;
char s[N][N];
int f[N][N];
int up[N][N];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin >> n >> m;
for(int i = 1;i<=n;++i)
{
cin >> s[i]+1;
}
for(int i = 1;i<=m;++i)
{
for(int j = 1;j<=n;++j)
{
int jj = j-1;
if(s[j][i] == s[jj][i])
{
up[j][i] = up[j-1][i]+1;
}
else
{
up[j][i] = 1;
}
}
}
long long sum = 0;
for(int i = 1;i<=n;++i)
{
for(int j = 1;j<=m;++j)
{
int ii = i-1,jj = j-1,j_ = j+1;
if(s[ii][jj] == s[ii][j_]&&s[ii][j_] == s[i][j])
{
f[i][j] = min(min(f[ii][jj],f[ii][j_])+1,up[i][j]+1>>1);
}
else
{
f[i][j] = 1;
}
sum+=f[i][j];
}
}
cout << sum;
return 0;
}
:::
总结
没想到这种类型的计数题竟然能用 DP,强强!?
尾声
如果你也想让这篇题解被更多萌新看到,请你点一个小小的赞,助力我的文章造福更多萌新,谢谢你们!