社团游戏【二分 + 递推】

tech2022-07-06  236

题目描述

在民风淳朴的雏见泽,号称能“完美犯罪”的天才牛牛,又开始和社团的萌妹子牛妹玩起了游戏。

在今天的游戏中,牛牛将会得到一个n×mn\times mn×m且全为小写字母的矩阵,他可以从矩阵中任选一块正方形,但必须保证该正方形中任意一类小写字母个数之和不能超过kkk,换而言之,在该正方形中,‘a’字符个数不能超过kkk,‘b’字符个数不能超过kkk,…,‘z’字符个数不能超过kkk。

现在牛牛想知道,以(i,j)(i,j)(i,j)为左上角且符合以上要求的正方形中,边长最大的是多少?

输入描述:

第一行三个正整数nnn,mmm,kkk,其中:n≤500n\leq500n≤500,m≤500m\leq500m≤500,k≤109k\leq10^{9}k≤109。

接下来nnn行,每行mmm个小写字母。

输出描述:

输出nnn行,每行mmm个数字。其中第iii行第jjj个数字表示,以(i,j)(i,j)(i,j)为左上角且符合题目要求的正方形的最大边长。

示例1 输入 复制

3 3 2 aaa bcd efg

输出 复制

2 2 1 2 2 1 1 1 1

#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int maxn = 1e3 + 10; int dp[30][maxn][maxn]; char a[maxn][maxn]; int ans[maxn][maxn]; int n, m, k; void init() { for(int k = 0; k < 26; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) dp[k][i][j] = dp[k][i - 1][j] + dp[k][i][j - 1] - dp[k][i - 1][j - 1] + (a[i][j] == k + 'a'); } } } bool judge(int x1, int y1, int x2, int y2) { for(int i = 0; i < 26; i++) { if(dp[i][x2][y2] - dp[i][x1 - 1][y2] - dp[i][x2][y1 - 1] + dp[i][x1 - 1][y1- 1] > k) return false; } return true; } void solve() { for(int i= 1; i <= n; i++) { for(int j =1 ; j <= m; j++) { int l = 1, r = min(n - i + 1, m - j + 1), ans = 1; while(l <= r) { int mid = l + r >> 1; if(judge(i, j, i + mid - 1, j + mid - 1)) l = mid + 1, ans = mid; else r = mid - 1; } cout << ans << " "; } cout << endl; } } int main() { cin >> n >> m >> k; for(int i = 1; i <= n; i++) cin >> a[i] + 1; init(); solve(); return 0; }
最新回复(0)