CF EDU#round 49 E题题解
题意:给你一个矩形,在他上面涂黑色或者白色,对于每一行
i
(
i
>
2
)
i(i>2)
i(i>2)要么这一行涂色和上一行相同,要么这一行每一个格子都和上一行不同,问不出现面积大于等于K的字矩形的总涂法
思路:可以把这个矩形编码成两个二进制串,然后设
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]为一个长度为i,与编码最后一个数字形成的后缀连通块长度为j,最长连续相同子串为k的二进制编码的个数,则转移方程为
d
p
[
i
+
1
]
[
j
+
1
]
[
m
a
x
(
k
,
j
+
1
)
]
+
=
d
p
[
i
]
[
j
]
[
k
]
(
m
o
d
 
p
)
d
p
[
i
]
[
1
]
[
m
a
x
(
1
,
k
+
1
)
]
+
=
d
p
[
i
]
[
j
]
[
k
]
(
m
o
d
 
p
)
dp[i+1][j+1][max(k,j+1)]+=dp[i][j][k](mod\thinspace p)\\dp[i][1][max(1,k+1)]+=dp[i][j][k](mod\thinspace p)
dp[i+1][j+1][max(k,j+1)]+=dp[i][j][k](modp)dp[i][1][max(1,k+1)]+=dp[i][j][k](modp)
最终求两个长度相乘不超过k的编码,运用加法原理和乘法原理即可
因为编码出来的两个串如果完全相反,他们表示的矩阵是一样的,所以答案除以2.然后内存不够的话滚动数组一下,具体看代码
代码:
#include <fstream>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <sstream>
#include <string>
#include <map>
#include <functional>
#include <queue>
#include <vector>
#include <set>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
#define maxn 1000005
ll mod=998244353;
ll dp[2][505][505],pre[505],cnt[505];
int main()
{
ll ans=0;
int n,k;
scanf("%d%d",&n,&k);
dp[0][0][0]=1;
for(int i=0;i<=n;i++)
{
int now=(i+1)&1,pre=i&1;
memset(dp[now],0,sizeof(dp[now]));
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
{
dp[now][j+1][max(j+1,k)]=(dp[now][j+1][max(j+1,k)]+dp[pre][j][k])%mod;
dp[now][1][max(1,k)]=(dp[now][1][max(1,k)]+dp[pre][j][k])%mod;
}
}
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
cnt[k]=(cnt[k]+dp[n&1][j][k])%mod;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i*j<k)ans=(ans+cnt[i]*cnt[j]%mod)%mod;
printf("%lld\n",(ans* (ll)((mod + 1) / 2) % mod)%mod);
return 0;
}