蓝桥杯 20531黑客java

问题描述

小蓝正在两台电脑之间拷贝数据,数据是一个 n×mn×m 大小的正整数矩阵,因此总共有 n×m+2n×m+2 个由空格分开的整数,其中前两个整数分别为 nn 和 mm。

然而,有黑客入侵了小蓝的电脑,导致这 n×m+2n×m+2 个正整数的顺序被打乱。小蓝想知道最多可能有多少个不同的原矩阵。

两个矩阵相同当且仅当它们的行数、列数分别相同,且每个位置上的数相同。

输入格式

输入的第一行包含一个正整数 n×m+2n×m+2。

第二行包含 n×m+2n×m+2 个正整数 a1,a2,...,an×m+2a1​,a2​,...,an×m+2​, 相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数,表示可能的不同原矩阵数量。答案可能很大,请输出答案除以 10000000071000000007 的余数。

样例输入

复制代码
6
2 2 1 4 3 3

样例输出

复制代码
24

样例说明

  1. (n,m)=(1,4)(n,m)=(1,4):有 66 种原矩阵:(2,2,3,3)(2,2,3,3), (2,3,2,3)(2,3,2,3), (2,3,3,2)(2,3,3,2), (3,2,2,3)(3,2,2,3), (3,2,3,2)(3,2,3,2), (3,3,2,2)(3,3,2,2);
  2. (n,m)=(4,1)(n,m)=(4,1):有 66 种原矩阵;
  3. (n,m)=(2,2)(n,m)=(2,2):有 1212 种原矩阵。

评测用例规模与约定

对于 40%的评测用例,1≤n×m+2≤101≤n×m+2≤10;

对于所有评测用例,1≤n×m+2≤5×1051≤n×m+2≤5×105, 1≤ai≤5×1051≤ai​≤5×105。

解题思路

这道题可以理解为:从n*m+2个数中取出来2个数作为矩阵的行数和列数并让kn-1,km-1,然后看剩下的数能组成多少种矩阵,我们可以把矩阵看作一行,对结果并没有影响,那么就转换为求剩下的数有多少种排列组合,公式为

N!

w=------------------------------ %MOD 其中ki是i出现的次数,N为n*m 之后把每种n,m的组合累加即可

k₁!*k₂!。。。kⁿ!

这里需要注意,这个公式我们需要用到乘法逆元,原因是:

N! N!%MOD

------------------------------ %MOD != ------------------------------

k₁!*k₂!。。。kⁿ! ( k₁!*k₂!。。。kⁿ!)%MOD

p 是质数,且 ap 互质,则:a^(p-2) ≡ a^(-1) (mod p)pa 的乘法逆元 = a^(p-2) mod p

如果仔细观察会发现,每找到一组n,m我们都得重新计算w,所有我们可以先求出所有数的 w,即不减去n和m这两个数,之后w再*n*m,并且(i,j)和(j,i)这两种情况实际上是相同的,让其中一个乘二即可,当n*m=N并且n=m时不需要乘二特判一下就行,阶乘也要预处理一下。

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        int MOD = 1000000007;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int s = Integer.parseInt(br.readLine());
        String num[] = br.readLine().split(" ");
        int N = s - 2;//矩阵中的个数
        long count = 0;//不同原矩阵的总数
        int geshu[] = new int[500001];
        long sum[] = new long[500001];//阶乘
        sum[0] = 1;
        long w = 1;//公共系数
        for (int i = 1; i <= 500000; i++) {
            sum[i] = (sum[i - 1] * i) % MOD;
        }
        for (int i = 0; i < num.length; i++) {
            geshu[Integer.parseInt(num[i])]++;
        }
        long D = 1;//D为各个数字出现次数的阶乘的积
        for (int i = 1; i <= 500000; i++) {
            D = (int) (D * sum[geshu[i]] % MOD);
        }
        long res = 1;//逆元
        long pow = MOD - 2;
        long base = D;
        base = base % MOD; // 先取模避免溢出
        while (pow > 0) {
            if (pow % 2 == 1) { // 奇数幂,乘到结果中
                res = (res * base) % MOD;
            }
            base = (base * base) % MOD; // 底数平方
            pow /= 2; // 指数折半
        }
        w = (int) (sum[N] * res % MOD);
        //枚举n,m并计算count
        for (int n=1;n<Math.sqrt(N);n++){
            if (N%n==0&&geshu[n]>0){
                int m=N/n;
                if (geshu[m]>0){
                    count = (count + 2*w*geshu[n]*geshu[m]%MOD) % MOD;
                }
            }
        }
        //n=m且n*m=N的特判
        int sqrtN=(int)Math.sqrt(N);
        if (sqrtN*sqrtN==N){
            if (geshu[sqrtN]>1){
                count=(count+w*geshu[sqrtN]*(geshu[sqrtN]-1))%MOD;
            }
        }
        System.out.println(count);
    }
}
相关推荐
leoufung2 小时前
LeetCode 427:Construct Quad Tree 题解与两种思路对比
算法·leetcode·职场和发展
阿拉伯柠檬2 小时前
C++中的继承
开发语言·数据结构·c++·面试
有点。2 小时前
C++ ⼀级 2025 年09 ⽉
开发语言·c++
2501_941982052 小时前
复杂消息格式自动化:图片、视频和自定义卡片的消息体构造
开发语言·php
ZePingPingZe2 小时前
Spring Boot常见注解
java·spring boot·后端
星辰烈龙2 小时前
黑马程序员Java基础8
java·开发语言
蒙奇D索大2 小时前
【数据结构】考研408 | 红黑树收官与B树启航:删除策略与多路平衡解析
数据结构·笔记·b树·考研·改行学it
毕设源码-郭学长2 小时前
【开题答辩全过程】以 公司考勤系统为例,包含答辩的问题和答案
java
SimonKing2 小时前
镜像拉不下来怎么办?境内Docker镜像状态在线监控来了
java·后端·程序员