CF EDU#round 49 E题题解

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值