洛谷 P1736 创意吃鱼法

解决猫猫如何在01矩阵代表的池塘中找到最大的正方形子矩阵,使得其一条对角线上都是1(代表有鱼),而其他位置都是0,并计算猫猫最多能一口吃掉多少条鱼。

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

题目描述

回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。

在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。

猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?

输入输出格式

输入格式:
有多组输入数据,每组数据:

第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。

对于30%的数据,有n,m≤100

对于60%的数据,有n,m≤1000

对于100%的数据,有n,m≤2500

输出格式:
只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。

输入输出样例

输入样例#1:
4 6
0 1 0 1 0 0
0 0 1 0 1 0
1 1 0 0 0 1
0 1 1 0 1 0
输出样例#1:
3
(一口能吃几百条鱼??)

分析:
设l[i,j]为第i行第j列数左边有多少个0,u[i,j]为第i行第j列数上边有多少个0,f[i,j]以第i行第j列为右下角的符合条件的最大正方形边长(就是一口能吃的数量)

f[i,j]=min(l[i,j],u[i,j],f[i-1,j-1])+1

当然,要考虑两种对角线(为左上到右下,和右上到左下),上面的方程为左上到右下,所以要把正方形进行翻转(把每一行的最左边变到最右边,左数第n个变到右数第n个),再跑一次DP即可。

代码:

var
 n,m,i,j,ans,x,min:longint;
 a,u,l:array [0..2501,0..2501] of longint;
 f:array [0..2501,0..2501] of longint;

procedure dp;
begin
 fillchar(f,sizeof(f),0);
 fillchar(u,sizeof(u),0);
 fillchar(l,sizeof(l),0);
 for i:=1 to n do
  for j:=1 to m do
   begin
    if i>1 then
     if (a[i-1,j]=0) then u[i,j]:=u[i-1,j]+1;
    if j>1 then
     if (a[i,j-1]=0) then l[i,j]:=l[i,j-1]+1;
    if a[i,j]=0 then continue;
    if u[i,j]>l[i,j] then min:=l[i,j]
                     else min:=u[i,j];
    if min>f[i-1,j-1] then
     f[i,j]:=f[i-1,j-1]+1
    else f[i,j]:=min+1;
    if f[i,j]>ans then ans:=f[i,j];
   end;
end;

begin
 readln(n,m);
 for i:=1 to n do
  for j:=1 to m do
    read(a[i,j]);
 dp;
 for i:=1 to n do
  for j:=1 to (m+1) div 2 do
   begin
    x:=a[i,j]; a[i,j]:=a[i,m+1-j]; a[i,m+1-j]:=x;
   end;
 dp;
 writeln(ans);
end.
### 洛谷 P3925 小猫分鱼 的算法分析 #### 问题描述 给定两个正整数 $N$ 和 $i$,表示有 $N$ 只小猫要分一堆鱼。初始时有一堆数量未知的鱼,记作 $X$。按照如下规则分配: 1. 如果当前剩余鱼的数量可以被 $(N-1)$ 整除,则将其中的一份(即 $\frac{X}{(N-1)}$)丢弃; 2. 剩下的部分平均分给剩下的 $N$ 只小猫。 最终目标是找到最小的可能的初始鱼的数量 $X$,使得经过若干次操作后能够完成上述过程[^1]。 --- #### 解题思路 该问题的核心在于模拟整个分配流程并验证是否存在符合条件的初始值 $X$。以下是具体的解决方法: 1. **变量定义** - 设初始鱼的数量为 $X$。 - 对于任意时刻,设当前鱼的数量为 `ans`,则其计算方式为: \[ ans = j \cdot N + i \] 其中 $j$ 是一个试探性的系数,用于寻找满足条件的最小值。 2. **循环判断合法性** - 使用外层循环不断增大 $j$ 的值,直到找到第一个满足条件的情况为止。 - 内部通过嵌套循环逐步检验每一轮的操作是否合法。具体来说,在第 $k$ 轮 ($1 \leq k < N$),需要检查当前鱼的数量能否被 $(N-1)$ 整除。如果不成立,则退出本轮尝试;否则继续下一轮。 3. **终止条件** - 当某轮迭代完成后未触发任何非法状态(即全程都能成功执行),即可认为找到了合适的解,并输出对应的 `ans` 值。 4. **复杂度分析** 外层循环次数取决于输入规模以及数据特性,但由于每次都会增加固定步长,因此总体效率较高。内部逻辑主要涉及简单的模运算与乘法操作,时间开销较小。 --- #### C++ 实现代码 下面是基于以上策略编写的完整程序: ```cpp #include <bits/stdc++.h> using namespace std; int main() { long long n, i; cin >> n >> i; // 输入参数 N 和 i for (long long j = 1;; ++j) { // 枚举试探系数 j bool flag = true; // 标志位记录当前方案是否可行 long long ans = j * n + i; // 初始化当前总鱼量 for (long long k = 1; k < n && flag; ++k) { // 进行 N-1 步模拟 if (ans % (n - 1)) { // 判断是否能整除 (N-1) flag = false; // 若无法整除,则标记失败 break; } ans = ans / (n - 1) * n + i; // 更新下一阶段的鱼总量 } if (flag) { // 找到首个合法方案 cout << ans << endl; return 0; } } } ``` --- #### 关键点说明 1. **初始化公式** 初始鱼的数量可以通过设置不同的倍数值来调整范围,从而覆盖所有潜在可能性[^4]。 2. **逐级验证机制** 在每一次试验过程中都需要严格遵循既定规则逐一校验各环节的状态变化情况,只有当全部步骤均无异常发生时才认定此候选答案有效[^3]。 3. **边界处理技巧** 特别注意极端情形下的行为表现,比如仅有两只会东西的小动物或者刚好处于临界点附近的测试样例等特殊场景[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值