1 条题解

  • 0
    @ 2025-8-24 22:38:12

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Suzt_ilymtics
    公主与玫瑰,随时待骑士归来 | AFO | SDUer

    搬运于2025-08-24 22:38:12,当前版本为作者最后更新于2022-05-12 21:46:20,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目要求很清楚不再赘述。

    首先我们有一个 O(n6)\mathcal O(n^6) 的暴力,直接按照题意模拟,期望得分 1010

    然后我们很自然的想到了使用二位前缀和,枚举所有的子矩阵进行一个贡献的统计。复杂度是 O(n4)\mathcal O(n^4),期望得分 3030

    然后我们找一下这题有什么特殊的地方:

    1ci,j1091 \le c_{i,j} \le 10^9

    也就是说,如果一个矩形是另一个矩形的子矩形,那么这个矩形肯定比另一个矩形的和小。

    看起来和单调性有关。

    那么,我们考虑枚举矩形的上边界,再枚举下边界,然后枚举左边界,那么右边界越向右整个矩阵的和越大,但是我们只想让这个和 ss 尽可能的接近 [a,b][a,b] (这里设 aba\le b)。

    那么我们可以二分一个位置,我们可以找到 <a<a 的最大的 ss 的位置和 >b>b 的最小的 ss 的位置然后对答案取 min\min(当然如果有 ss 满足 asba \le s \le b,那么答案也就被确定为 bab-a 了)

    但是这样我们的复杂度是 O(n3logn)\mathcal O(n^3 \log n) 的,依然不能通过。

    发现我们二分的这个位置,随着固定的左端点右移,这个位置也不断右移,因此我们可以拿双指针从左向右扫一遍,并在扫的过程中对答案取 min\min 就好了。(顺便判断一下有无 asba \le s \le b 的情况)

    这样复杂度是 O(n3)\mathcal O(n^3) 的,可以通过。

    代码实现可以参考一下我的,但是我感觉还是理解后自己实现更为好写,因为我写的很丑

    #include<bits/stdc++.h>
    #define LL long long 
    #define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    int read() {
        int s = 0, f = 0; char ch = getchar();
        while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
        return f ? -s : s;
    }
    
    int n, m, A, B;
    int a[555][555];
    int b[555];
    int sum[555][555];
    
    signed main() {
    	n = read(), m = read(), A = read(), B = read();
    	if(A > B) swap(A, B);
    	for(register int i = 1; i <= n; ++i) {
    		for(register int j = 1; j <= m; ++j) {
    			a[i][j] = read();
    			sum[i][j] = sum[i - 1][j] + a[i][j];
    		}
    	}
    	int ans = abs(a[1][1] - A) + abs(a[1][1] - B);
    	for(register int l = 1; l <= n; ++l) {
    		for(register int r = l; r <= n; ++r) {
    			for(register int i = 1; i <= m; ++i) b[i] = sum[r][i] - sum[l - 1][i];
    			int R = 0, now = 0;
    			while(R < m && now + b[R + 1] < A) now += b[++R];
    			for(register int L = 1; L <= m; ++L) {
    				if(R < m && now + b[R + 1] >= A && now + b[R + 1] <= B) return printf("%lld\n", B - A), 0;
    				ans = min(ans, abs(now - A) + abs(now - B));
    				now -= b[L];
    				while(R < m && now + b[R + 1] <= A) now += b[++R];
    			}
    			R = 0, now = 0;
    			while(R < m && now <= B) now += b[++R];
    			for(register int L = 1; L <= m; ++L) {
    				ans = min(ans, abs(now - A) + abs(now - B));
    				now -= b[L];
    				if(now >= A && now <= B) return printf("%lld\n", B - A), 0;
    				while(R < m && now <= B) now += b[++R]; 
    			}
    		}
    	}
    	printf("%lld\n", ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    7680
    时间
    2000ms
    内存
    512MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者