蓝桥杯 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);
    }
}
相关推荐
Wect17 分钟前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
Re_zero23 分钟前
线上日志被清空?这段仅10行的 IO 代码里竟然藏着3个毒瘤
java·后端
洋洋技术笔记29 分钟前
Spring Boot条件注解详解
java·spring boot
NAGNIP12 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
程序员清风18 小时前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林55120 小时前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
颜酱20 小时前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub1 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉