1 条题解

  • 0
    @ 2026-4-29 14:16:01

    注意到第一条路经肯定是每一步能往右就往右,否则往下,然后每次从下往上扩展。

    首先我们发现答案就是洞数量的集合,因为如果一条路径可以达到某个数值,那么数值更大的路径从左往右到达 (n,m)(n,m) 的时候必然会与这条路径相交。

    如图:

    橙色路径后面与黑色路径相交,可见这种相交是必然,交点之后的路径如果有数值更小的那以前肯定走过了,所以不用再走了,所以我们暴力搜索,每次能往右边就往右边,一旦发现自己走到的点以前走过了,就把从这个点走到 (n,m) 能产生的最大数值 和当前已有数值相加加入集合,这是因为后半程已经走过了答案更小的,为了让下一条路径完全包含以前的路径,必须走数值最大的。

    这样复杂度 O(nm)O(nm)

    代码:

    #include <bits/stdc++.h>
    
    #define int long long
    
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int n, m, sum[2005][2005];
    
    char s[2005][2005];
    
    bool is[2005][2005], ok[2005 * 2005];
    
    int len[2005][2005];
    
    void dfs (int i, int j, int cnt) {
    	if (i > n || j > m || s[i][j] == '#') return;
    	if (is[i][j]) {
    		if (len[i][j] + cnt >= 0) ok[len[i][j] + cnt] = true;
    		return;
    	}
    	if (i == n && j == m) {
    		ok[cnt] = true;
    		len[i][j] = 0;
    		return;
    	}
    	is[i][j] = true;
    	dfs (i, j + 1, cnt + sum[i][j + 1]);
    	len[i][j] = max(len[i][j], len[i][j + 1] + sum[i][j + 1]);
    	dfs (i + 1, j, cnt);
    	len[i][j] = max(len[i][j], len[i + 1][j]);
    	return;
    }
    
    signed main() {
    //	freopen("grid.in","r",stdin);
    //	freopen("grid.out","w",stdout);
    	memset(len, -0x3f, sizeof(len));
    	scanf("%lld%lld", &n, &m);
    	for (int i = 1; i <= n; ++ i ) scanf("%s", s[i] + 1);
    	for (int j = 1; j <= m; ++ j )
    	    for (int i = 1; i <= n; ++ i )
    	        sum[i][j] = sum[i - 1][j] + (s[i][j] == '#');
    	    
    	dfs (1, 1, 0);
    	int ans = 0;
    	for (int i = 0; i <= n * m; ++ i ) ans += ok[i];
    	printf("%lld\n", ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    11139
    时间
    1000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者