前言

「算法题解」系列致力于分享有价值的题目、探讨更优秀的解法。

这是本系列的第 30 篇题解,更多题解关注 Somnia1337@力扣。

终于来到了本次蓝桥杯 8 题的最后一题🙌

H. 智力测试

题目描述

一个 的棋盘,每行、每列都有一个正整数权值(分别记为数组 rowcol),每次可从当前方格 (x1, y1) 跳到任意方格 (x2, y2),但需满足:

  • x1 == x2 && y1 != y2 && col[y2] > col[y1]x1 != x2 && y1 == y2 && row[x2] > row[x1](即只能在同行 / 同列跳动,且目标方格的对应权值大于起点方格)
  • 对如上 2 种情况,分别不存在 y3x3,使得 col[y2] > col[y3] > col[y1]row[x2] > row[x3] > row[x1](即不能跳过中间权值)

多次询问,每次给定起、止方格,回答合法的路径方案数(没有记为 0)对 1000000007 取余。

输入输出示例

输入共 3 + q 行,第 1 行含三个正整数 nmq,第 2 行含 n 个正整数表示各行的权值,第 3 行含 m 个正整数表示各列的权值,随后 q 行各含四个正整数表示 x1y1x2y2

4 4 2
4 2 3 1
2 1 2 1
4 4 1 1
2 2 2 4

范围:

  • nmT
  • RC
  • x1x2 n
  • y1y2 m

输出 q 行,每行含一个正整数表示对该次询问的回答:

4
0

解题思路

x、y 两方向上的移动是独立的,记分别的移动步数为 mxmy,则最终答案为

假设列的权值为 [1, 2, 3, 2, 2, 4, 3]

排序后为 [1, 2, 2, 2, 3, 3, 4]

起点 y == 0col[y1] == 1),终点 y == 5col[y2] == 4),则 my 为:

  • 1 走到 2 步数为 ,走到 3 步数为 ,走到 4 步数为
  • 2 次重复,3 次重复,步数先减去 ,再乘以

因此 my == 8,同理算得 mx,求组合数即可。

答案

截至发文,dotcpp 上还未开放作答本题目。

import java.util.*;
import java.io.*;
import java.math.BigInteger;
 
public class Main {
    private static final int M = 1000000007;
    private static final BigInteger BM = BigInteger.valueOf(M);
    
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(System.out);
        
        StringTokenizer st = new StringTokenizer(in.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int q = Integer.parseInt(st.nextToken());
        
        int[] row = new int[n];
        st = new StringTokenizer(in.readLine());
        for (int i = 0; i < n; i++) {
            row[i] = Integer.parseInt(st.nextToken());
        }
        int[] sortedRow = new int[n];
        System.arraycopy(row, 0, sortedRow, 0, n);
        Arrays.sort(sortedRow);
        
        int[] col = new int[m];
        st = new StringTokenizer(in.readLine());
        for (int j = 0; j < m; j++) {
            col[j] = Integer.parseInt(st.nextToken());
        }
        int[] sortedCol = new int[m];
        System.arraycopy(col, 0, sortedCol, 0, m);
        Arrays.sort(sortedCol);
        
        while (q-- > 0) {
            st = new StringTokenizer(in.readLine());
            int x1 = Integer.parseInt(st.nextToken()) - 1;
            int y1 = Integer.parseInt(st.nextToken()) - 1;
            int x2 = Integer.parseInt(st.nextToken()) - 1;
            int y2 = Integer.parseInt(st.nextToken()) - 1;
            
            boolean validX = row[x1] < row[x2] || row[x1] == row[x2] && x1 == x2;
            boolean validY = col[y1] < col[y2] || col[y1] == col[y2] && y1 == y2;
            if (!(validX && validY)) {
                out.println(0);
                continue;
            }
            
            int movX = moves(sortedRow, row[x1], row[x2]);
            int movY = moves(sortedCol, col[y1], col[y2]);
            out.println(comb(movX + movY, Math.min(movX, movY)));
        }
        
        out.flush();
        out.close();
    }
    
    private static int moves(int[] sortedA, int src, int dest) {
        long mov = 0;
        int pre = -1;
        int streak = 0;
        boolean minus = false;
        for (int p : sortedA) {
            if (p <= src) continue;
            if (p == pre) {
                if (!minus) {
                    mov--;
                    minus = true;
                }
                streak++;
            }
            else {
                minus = false;
                pre = p;
                mov++;
            }
            if (p == dest) break;
        }
        
        for (int k = 0; k < streak; k++) {
            mov = (mov << 1) % M;
        }
        return (int) mov;
    }
    
    private static BigInteger comb(int from, int choice) {
        BigInteger r = BigInteger.valueOf(1);
        
        for (int x = from; x > from - choice; x--) {
            r = r.multiply(BigInteger.valueOf(x));
        }
        for (int x = choice; x >= 2; x--) {
            r = r.divide(BigInteger.valueOf(x));
        }
        
        r = r.mod(BM);
        return r;
    }
}