Educational Codeforces Round 49 E. Inverse Coloring(思维,差分,dp)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 49 E. Inverse Coloring(思维,差分,dp)相关的知识,希望对你有一定的参考价值。
题意
给出一个 n ∗ n n*n n∗n的矩阵,要求在每个位置涂上黑/白色,要求满足:
任意相邻的两行,其颜色要么完全相同,要么完全相反。
任意相邻的两列,其颜色也要么相同要么完全相反。
且这个矩形中,不存在任意一个大小大于等于k的同色矩形。
求方案数
第一个比较有技巧的点是一个矩形确定了第一行第一列的颜色后,整个矩形的颜色就被确定了
现在考虑怎样来判断是否存在大于等于 k k k的同色矩形,我们只需要找到最大的那个是否小于 k k k即可
我们先计算第一行最大连续同色段长为 x x x,第一列为 y y y
那么 x ∗ y < k x*y<k x∗y<k就满足条件(对应的子矩阵一定最大且同色)
因为第一行和第一列有公共位置,不妨先假设这个位置是白色,之后把答案乘以 2 2 2即可
于是问题转化为,若能计算数组 f [ i ] [ j ] f[i][j] f[i][j]表示长度为 i i i最长同色段为 j j j的方案数
显然第一行和第一列的方案数都可以用这个数组来描述
答案即为
∑ i ∗ j < k ( f [ n ] [ i ] ∗ f [ n ] [ j ] [ ) \\sum\\limits_{i*j<k}(f[n][i]*f[n][j][ ) i∗j<k∑(f[n][i]∗f[n][j][)
不过似乎这个并不好快速转移,我们先定义 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i个格子最大连续段不超过 j j j的方案
于是我们每次去枚举一整段颜色相同的段即可,转移方程为
d p [ i ] [ j ] + = = d p [ i − z ] [ j ] ( z < = min ( i , j ) ) dp[i][j]+==dp[i-z][j]\\ (z<=\\min(i,j)) dp[i][j]+==dp[i−z][j] (z<=min(i,j))
初始化 d p [ 0 ] [ i ] = 1 dp[0][i]=1 dp[0][i]=1
那么显然 f [ n ] [ i ] = d p [ n ] [ i ] − d p [ n ] [ i − 1 ] f[n][i]=dp[n][i]-dp[n][i-1] f[n][i]=dp[n][i]−dp[n][i−1]
问题得到解.
一开始我还在纠结,第一行和第一列其实是有一个公共点的,那是这样直接乘起来不是没有考虑公共点吗?
其实不是的,因为我们枚举的是同色段,没有具体规定是那种颜色,所以是独立的,是正确的方案
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int maxn = 509;
int t,n,k,f[501][501],ans[maxn];
signed main()
{
cin >> n >> k;
for(int i=1;i<=n;i++) f[0][i] = 1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=min(j,i);k++)
f[i][j] = ( f[i][j]+f[i-k][j] )%mod;
for(int i=1;i<=n;i++) ans[i] = ( f[n][i]-f[n][i-1] )%mod;
int res = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if( i*j<k ) res = ( res+ans[i]*ans[j]%mod )%mod;
cout << ( res*2+mod )%mod;
}
以上是关于Educational Codeforces Round 49 E. Inverse Coloring(思维,差分,dp)的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 7 A
Educational Codeforces Round 7
Educational Codeforces Round 90
Educational Codeforces Round 33