本题看似很难,实际上只需要找找规律就好。
先从样例入手。
样例给的例子是只有两行的特殊情况,我们可以先从这个特殊情况入手。
我们发现,当一条线向下穿过的时候,设与中间的线交点为 P。那么如果 P 不在格点上时,下一行就会从这列开始,如果 P 在格点上,那么就会从下一列开始。显然,前一种会比后一种多一个格子,所以只有前种策略最优。
再把问题的范围扩大到一般情况,有了上面的结论,我们可以发现,如果总格子是 n × m n\times m n×m。那么最优解一定是 n + m − 1 n+m-1 n+m−1,证明如下。
首先这条线可以水平切,那么就是 n n n 个格子,然后我们再固定一端,把另一端向下移动。当这条线穿过了两行时,如果与中间的线的交点不在格点上,那么就会多出一个格子。再继续向下移动,直到穿过了 m m m 行,这时一共交了 m − 1 m-1 m−1 条水平线,最多多产生 m − 1 m-1 m−1 个格子被穿过。
综上所述,当总格子是 n × m n\times m n×m 时,最多可穿过 n + m − 1 n+m-1 n+m−1 个格子。
于是,第一个问题就很容易地解决了。
再看看第二个问题,如果想要穿过的格子数大于等于 Q Q Q,也就代表 n ′ + m ′ − 1 n'+m'-1 n′+m′−1 最小也要等于 Q Q Q。也就是说我们知道了 n ′ + m ′ n'+m' n′+m′ 想要求满足 n ′ ≤ n , m ′ ≤ m n'\leq n,m'\leq m n′≤n,m′≤m 的情况下,使得 n ′ × m ′ n'\times m' n′×m′ 最小。
小学数学老师告诉我们,矩形周长一定时,长宽差距越小,面积越大。所以, n ′ n' n′ 或者 m ′ m' m′ 某一个尽可能的小就可以让 n ′ × m ′ n'\times m' n′×m′ 尽可能的大。显然,如果 n > m n>m n>m ,就让 m ′ = m , n ′ = Q + 1 − m m'=m,n'=Q+1-m m′=m,n′=Q+1−m,反之同理。
因为无论是 n ′ = n n'=n n′=n 还是 m ′ = m m'=m m′=m,对应的 m ′ − m m'-m m′−m 和 n ′ − n n'-n n′−n 的值都是 Q + 1 − n − m Q+1-n-m Q+1−n−m。所以第二问的答案就是 min ( n , m ) × ( Q + 1 − n − m ) \min(n,m)\times(Q+1-n-m) min(n,m)×(Q+1−n−m)。
AC 代码
#include<bits/stdc++.h>
using namespace std;
const unsigned long long mod=998244353;//因为数据比较大,所以我直接开的unsigned long long
unsigned long long n,m,k,d;
int T;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%llu%llu%llu",&k,&n,&m);
if(k==1) printf("%llu\n",n+m-1);
else scanf("%llu",&d),d=d+1-n-m,d%=mod,printf("%llu\n",min(n,m)%mod*d%mod);
}
return 0;
}