Codeforces 1027E Inverse Coloring【DP】

博客围绕一个n*n矩阵染色问题展开。要求矩阵方格染黑白两色,相邻行或列颜色完全相同或不同,且不存在面积大于k的单色小矩形。题解通过假设行列系数解决第一个要求,用差分和动态规划计算满足条件的染色方案数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

E. Inverse Coloring

You are given a square board, consisting of nn rows and nn columns. Each tile in it should be colored either white or black.

Let's call some coloring beautiful if each pair of adjacent rows are either the same or different in every position. The same condition should be held for the columns as well.

Let's call some coloring suitable if it is beautiful and there is no rectangle of the single color, consisting of at least kk tiles.

Your task is to count the number of suitable colorings of the board of the given size.

Since the answer can be very large, print it modulo 998244353998244353.

Input

A single line contains two integers nn and kk (1≤n≤5001≤n≤500, 1≤k≤n21≤k≤n2) — the number of rows and columns of the board and the maximum number of tiles inside the rectangle of the single color, respectively.

Output

Print a single integer — the number of suitable colorings of the board of the given size modulo 998244353998244353.

Examples

input

Copy

1 1

output

Copy

0

input

Copy

2 3

output

Copy

6

input

Copy

49 1808

output

Copy

359087121

Note

Board of size 1×11×1 is either a single black tile or a single white tile. Both of them include a rectangle of a single color, consisting of 11 tile.

Here are the beautiful colorings of a board of size 2×22×2 that don't include rectangles of a single color, consisting of at least 33 tiles:

The rest of beautiful colorings of a board of size 2×22×2 are the following:

题意:给一个n*n的矩阵染色,每个方格只能被然后黑色和白色。要求要满足任意两行或任意两列的颜色要完全相同或者完全不同。矩形内部不能存在一个面积大于k的由一种颜色组成的小矩形。

题解:首先我们假设每行有个系数a_i,每列有一个系数b_j则第i行第j列的颜色为a_i xor b_j。就可以巧妙的解决第一个要求。假设求出长度n的01串的最长连续0或1的个数为x设为d[x],那个当行最长连续与列最长连续的积小于k就可以满足要求。对于长度为n的最长连续长度为x的01串可以用差分求出来,设c[x]为长度最长连续长度小于等于x的个数,则d[x]=c[x]-c[x-1]。c[x]可以用dp维护。

设dp[i][j]为长度为i的最长连续小于j的个数,则转移方程为: dp[i][j]=\sum_{k=1}^{min(i,j)}dp[i-k][j]

 

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD=998244353;
LL dp[505][505],a[505];
int main()
{
    int n,k;printf("%.5f\n",(double)clock()/CLOCKS_PER_SEC);
    scanf("%d%d",&n,&k);

    for(int i=1; i<=n; i++)
    {
        dp[i][0]=1;
        for(int j=1; j<=n; j++)
            for(int k=1; k<=min(i,j); k++)
                dp[i][j]=(dp[i][j]+dp[i][j-k])%MOD;
    }
    for(int i=1; i<=n; i++)
        a[i]=(dp[i][n]-dp[i-1][n]+MOD)%MOD;
    LL ans=0;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            if(i*j<k)
                ans+=a[i]*a[j]%MOD;
    ans=ans*2%MOD;
    printf("%lld\n",ans);
}

 

### Codeforces Round 1027 题目与题解 Codeforces Round 1027 是一场面向不同水平选手的比赛,包含多道编程问题,涉及算法、数据结构以及数学知识。以下是部分题目及其对应的题解分析。 #### A. 示例题目(假设为“A. Simple Arithmetic”) **题目描述** 给定一个整数 \( x \),判断是否可以通过某种方式将 \( x \) 分解为若干个数字的和,并满足特定条件。 **题解** 此问题可以通过简单的模拟来解决。通过检查 \( x \) 的每一位数字是否符合要求,逐步缩小范围直至找到答案[^1]。以下是一个可能的实现代码: ```cpp #include <bits/stdc++.h> using namespace std; void solve() { long long x; cin >> x; while (x) { if (x > 0 && x < 10 || x % 10 == 9) { cout << "NO\n"; return; } x /= 10; x -= 1; } cout << "YES\n"; } ``` 上述代码通过逐位检查 \( x \) 的值是否满足条件,并在不满足时直接返回“NO”。 --- #### B. 中位数调整问题(假设为“B. Median Adjustment”) **题目描述** 给定一个数组,通过删除某些元素使得中位数向左或向右移动,最终形成一段连续的合法区间。 **题解** 为了实现中位数的调整,需要枚举每一段可能的区间并判断其合法性。如果目标是左移,则优先删除右侧端点;如果是右移,则删除左侧端点[^4]。代码示例如下: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<int> a(n); for (auto &x : a) cin >> x; // 枚举所有可能的区间 int result = 0; for (int l = 0; l < n; ++l) { vector<int> temp; for (int r = l; r < n; ++r) { temp.push_back(a[r]); // 判断当前区间是否合法 if (is_valid(temp)) result += 1; } } cout << result; } ``` 在此代码中,`is_valid` 函数用于验证当前区间的合法性[^4]。 --- #### C. 序列构造问题(假设为“C. Sequence Construction”) **题目描述** 给定两个整数 \( n \) 和 \( k \),构造一个大小不超过 25 的非负整数序列 \( a \),使得: 1. 存在一个子序列的和为任意 \( v \neq k \) 且 \( 1 \leq v \leq n \)。 2. 不存在任何子序列的和等于 \( k \)。 **题解** 此类问题的核心在于构造一个满足条件的序列。一种常见方法是通过贪心策略逐步添加元素,同时避免生成和为 \( k \) 的子序列[^3]。以下是一个可能的实现: ```cpp #include <bits/stdc++.h> using namespace std; vector<int> construct_sequence(int n, int k) { vector<int> res; for (int i = 1; i <= n && res.size() < 25; ++i) { if (i != k) res.push_back(i); // 检查是否存在和为 k 的子序列 if (has_subsequence_sum(res, k)) return {}; } return res; } bool has_subsequence_sum(const vector<int> &a, int k) { // 使用动态规划检查是否存在子序列和为 k vector<bool> dp(k + 1, false); dp[0] = true; for (auto x : a) { for (int j = k; j >= x; --j) { dp[j] |= dp[j - x]; } } return dp[k]; } ``` 上述代码通过动态规划验证是否存在和为 \( k \) 的子序列[^3]。 --- #### D. 路径众数问题(假设为“D. Path Majority”) **题目描述** 给定一棵树,判断是否存在一条路径,使得该路径上的众数(出现次数最多的节点值)超过路径总长度的一半。 **题解** 此问题可以通过深度优先搜索(DFS)结合众数统计的方法解决。关键在于观察到如果路径上存在众数,则必然会出现两个相同的节点值相邻或间隔一个节点的情况[^2]。因此可以直接对所有节点进行简单判断即可。 ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; vector<int> adj[MAXN]; int values[MAXN]; bool dfs(int u, int parent, int target) { int count = 0; if (values[u] == target) count += 1; for (auto v : adj[u]) { if (v != parent) { count += dfs(v, u, target); } } return count > (adj[u].size() + 1) / 2; } bool has_majority_path(int n) { for (int i = 1; i <= n; ++i) { if (dfs(i, -1, values[i])) return true; } return false; } ``` 上述代码通过递归检查每个节点是否可能成为路径上的众数[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值