当前位置: 首页 > wzjs >正文

南京做公司网站临沂做网站推广的公司

南京做公司网站,临沂做网站推广的公司,设计制作小车教学反思,十堰优化网站排名公司P1143 进制转换 解题思路 读取输入: 使用 Scanner 读取三个输入值:原进制 n,原进制数 s,目标进制 m。 进制转换: 使用 Integer.parseInt(s, n) 将原进制数 s 转换为十进制整数。使用 Integer.toString(decimalValue, …

P1143 进制转换

解题思路

  1. 读取输入
    • 使用 Scanner 读取三个输入值:原进制 n,原进制数 s,目标进制 m。
  2. 进制转换
    • 使用 Integer.parseInt(s, n) 将原进制数 s 转换为十进制整数。
    • 使用 Integer.toString(decimalValue, m) 将十进制整数转换为目标进制字符串。
    • 调用 .toUpperCase() 确保输出中的字母为大写。
  3. 输出结果
    • 打印转换后的目标进制数。
import java.util.Scanner;public class Main {public static void main(String[] args) throws Exception {Scanner input = new Scanner(System.in);// 读取输入int n = input.nextInt(); // 原进制String s = input.next(); // 原进制数int m = input.nextInt(); // 目标进制// 关闭输入流input.close();// 将原进制数转换为目标进制int decimalValue = Integer.parseInt(s, n);String result = Integer.toString(decimalValue, m).toUpperCase();// 输出结果System.out.println(result);}
}

P1469 找筷子 

解题思路

对于对内存有要求的题目不太适合使用Java完成,并且有规定不保证非C/C++语言可以通过题目,洛谷不会给非C/C++语言提供额外的时间和空间,所以该题大家最好使用C/C++完成,Java代码仅供参考。

该题通过异或运算的思路可以完美解决配对问题,异或运算的法则是相同为0,不同为1

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int ans = 0;while (n-- > 0) {ans ^= scanner.nextInt();}System.out.println(ans);scanner.close();}
}

P1100 高低位交换 

解题思路

1. 读取输入

  • 使用 Scanner 读取一个整数 num
  • input.nextInt() 读取的是一个有符号的 32 位整数。
  • 为了将其视为无符号整数,使用按位与操作 & 0xFFFFFFFFL
    • 0xFFFFFFFFL 是一个 64 位的掩码,保留输入整数的低 32 位。
    • 这样可以将负数转换为其无符号等价值(例如,-1 会被转换为 4294967295)。

2. 高低位交换

  1. 提取低 16 位(unsignedNum & 0x0000ffff

    • 使用按位与操作 & 0x0000ffff 提取无符号数的低 16 位。
    • 例如,unsignedNum = 0x12345678,则低 16 位为 0x5678
  2. 将低 16 位移到高 16 位((unsignedNum & 0x0000ffff) << 16

    • 使用左移操作 << 16 将低 16 位移动到高 16 位的位置。
  3. 提取高 16 位(unsignedNum & 0xffff0000)

    • 使用按位与操作 & 0xffff0000 提取无符号数的高 16 位。
    • 例如,unsignedNum = 0x12345678,则高 16 位为 0x1234
  4. 将高 16 位移到低 16 位((unsignedNum & 0xffff0000) >> 16)

    • 使用右移操作 >> 16 将高 16 位移动到低 16 位的位置。
    • 注意:由于 unsignedNum 是 long 类型,右移操作不会保留符号位。
  5. 合并高低位(((unsignedNum & 0x0000ffff) << 16 | (unsignedNum & 0xffff0000) >> 16))

    • 使用按位或操作 | 将交换后的高位和低位合并,得到最终结果。

3. 输出结果

import java.util.Scanner;public class Main {public static void main(String[] args) throws Exception {Scanner input = new Scanner(System.in);// 将读入的数转为无符号整型long unsignedNum = input.nextInt() & 0xFFFFFFFFL;// 输出结果System.out.println(((unsignedNum & 0x0000ffff) << 16 | (unsignedNum & 0xffff0000) >> 16));input.close();}
}

P1017 [NOIP 2000 提高组] 进制转换 

解题思路

  1. 输入读取

    • 使用 Scanner 读取十进制数 n 和负进制基数 r
  2. 负进制转换逻辑

    • 使用 n % r 计算余数。
    • 如果余数为负数,则调整余数为正数,同时将商 n 加 1。
    • 将余数转换为对应的字符:
      • 如果余数大于等于 10,使用 A 到 F 表示(类似于 16 进制)。
      • 否则直接添加数字。
  3. 结果构建

    • 使用 StringBuilder 构建结果,最后调用 reverse() 方法将结果反转(因为进制转换是从低位到高位计算的)。
  4. 特殊情况

    • 如果输入的 n 为 0,直接输出 0
  5. 输出格式

    • 按照题目要求输出:n=结果(baseR)
import java.util.Scanner;public class Main {public static void main(String[] args) throws Exception {Scanner input = new Scanner(System.in);// 读取输入的十进制数 n 和负进制基数 Rint n = input.nextInt();int r = input.nextInt();// 保存原始输入值,用于输出int originalN = n;// 用 StringBuilder 构建结果StringBuilder result = new StringBuilder();// 负进制转换while (n != 0) {int remainder = n % r;n /= r;// 如果余数为负数,调整余数和商if (remainder < 0) {remainder += Math.abs(r);n += 1;}// 将余数转换为对应的字符(支持大于 10 的数码)if (remainder >= 10) {result.append((char) ('A' + (remainder - 10)));} else {result.append(remainder);}}// 如果结果为空,表示输入为 0if (result.length() == 0) {result.append("0");}// 输出结果System.out.printf("%d=%s(base%d)\n", originalN, result.reverse().toString(), r);input.close();}
}

P1866 编号

解题思路

        1.排序:将兔子的编号范围按升序排序,优先处理编号范围较小的兔子。

        2.计算可选编号:对于第 i 只兔子,可选编号数量为 M[i] - i,因为前面 i 只兔子已经占用了 i 个编号。

        3.取模运算:每次乘法操作后对 10^9+7 取模,避免溢出。

import java.util.Arrays;
import java.util.Scanner;public class Main {public static void main(String[] args) throws Exception {Scanner input = new Scanner(System.in);int n = input.nextInt();int[] m = new int[n];for (int i = 0; i < m.length; i++) {m[i] = input.nextInt();}input.close();Arrays.sort(m);// modfinal int MOD = 1_000_000_007;long ans = 1;for (int i = 0; i < n; i++) {int choices = m[i] - i;if (choices <= 0) {ans = 0;break;}ans = (ans * choices) % MOD;}System.out.println(ans);}
}

P2822 [NOIP 2016 提高组] 组合数问题

解题思路

(1) 初始化组合数
  • 使用递推公式计算组合数: $ \binom{i}{j} = \binom{i-1}{j-1} + \binom{i-1}{j} $
  • 每次计算后对 $k$ 取模,避免溢出。
  • 如果 $\binom{i}{j} \mod k = 0$,则统计该组合数。
(2) 计算前缀和
  • 对于每行 $i$,计算满足条件的组合数的前缀和。
  • 前缀和公式:
    • 如果 $j < i$prefixSum[i][j] = prefixSum[i - 1][j] + count[i]
    • 如果 $j == i$(对角线特殊处理):prefixSum[i][j] = count[i] + prefixSum[i - 1][j - 1]
(3) 查询结果
  • 对于每个测试用例,读取$n$$m$
  • 确保 $m \leq n$,因为列数不能超过行数。
  • 直接通过 prefixSum 查询满足条件的组合数个数。
import java.util.Scanner;public class Main {static long[][] comb = new long[2001][2001]; // 存储组合数static long[] count = new long[2001]; // 每行满足条件的组合数个数static long[][] prefixSum = new long[2001][2001]; // 前缀和数组static long n, m, k;static int t;public static void main(String[] args) {Scanner ipnut = new Scanner(System.in);t = ipnut.nextInt();k = ipnut.nextLong();// 初始化组合数comb[0][0] = 1;for (int i = 1; i < 2001; i++) {comb[i][0] = 1;for (int j = 1; j <= i; j++) {// 递推计算组合数并取模comb[i][j] = (comb[i - 1][j - 1] + comb[i - 1][j]) % k;if (comb[i][j] == 0) {// 统计每行满足条件的组合数个数count[i]++;}// 计算前缀和prefixSum[i][j] = prefixSum[i - 1][j] + count[i];if (j == i) {// 特殊处理对角线prefixSum[i][j] = count[i] + prefixSum[i - 1][j - 1];}}}while (t-- > 0) {// 读取输入n = ipnut.nextLong();m = ipnut.nextLong();// 确保列数不超过行数if (m > n) {m = n;}// 输出结果System.out.println(prefixSum[(int) n][(int) m]);}ipnut.close();}
}

P2789 直线交点数

解题思路

本来没有思路,看了题解才明白,代码思路来源于洛谷题解。觉得有帮助的可以给题解作者点个免费的赞。

import java.util.Scanner;public class Main {static int n;static int MAX = -1;static int ans = 0;static boolean[] f = new boolean[11000];/*** 递归函数,用于计算所有可能的结果* * @param n 剩余的数* @param k 当前计算的结果*/public static void func(int n, int k) {// 如果剩余的数为 0,记录当前结果if (n == 0) {f[k] = true;                // 标记结果 k 为可达MAX = Math.max(k, MAX);     // 更新最大值} else {// 遍历所有可能的相交方式for (int r = n; r >= 1; r--) {// 递归调用,计算剩余部分func(n - r, r * (n - r) + k);}}}public static void main(String[] args) {Scanner input = new Scanner(System.in);n = input.nextInt();func(n, 0);for (int i = 0; i <= MAX; i++) {if (f[i]) {ans++;}}System.out.println(ans);input.close();}
}

P3913 车的攻击

解题思路

1. 排序

  • 对 rows 和 cols 数组进行排序:
    • 排序的目的是为了方便后续统计数组中不同元素的数量(去重)。

2. 统计不同行和列的数量

  • 调用 countDistinct 方法分别统计 rows 和 cols 中不同元素的数量:
    • r 表示不同的行数。
    • c 表示不同的列数。
  • countDistinct 方法的逻辑:
    • 遍历排序后的数组,统计相邻元素不同的次数,即为数组中不同元素的数量。

3. 计算覆盖的格子数量

  • 使用公式计算覆盖的格子数量:
    long result = (long) N * (r + c) - (long) r * c;
    • (N * (r + c)):表示所有被覆盖的行和列的格子数。
    • -(r * c):减去行列交叉的格子数,因为这些格子会被重复计算。
import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) throws IOException {// 使用 BufferedReader 读取输入,提高输入效率BufferedReader br = new BufferedReader(new InputStreamReader(System.in));// 使用 StringTokenizer 解析第一行输入,获取 N 和 KStringTokenizer st = new StringTokenizer(br.readLine());int N = Integer.parseInt(st.nextToken()); // 矩阵的大小 N x Nint K = Integer.parseInt(st.nextToken()); // 特殊点的数量 K// 定义两个数组分别存储特殊点的行和列int[] rows = new int[K];int[] cols = new int[K];// 读取 K 个特殊点的行列坐标for (int i = 0; i < K; i++) {st = new StringTokenizer(br.readLine());rows[i] = Integer.parseInt(st.nextToken()); // 读取行坐标cols[i] = Integer.parseInt(st.nextToken()); // 读取列坐标}// 对行和列的数组进行排序,方便后续去重统计Arrays.sort(rows);Arrays.sort(cols);// 统计行和列中不同的值的数量int r = countDistinct(rows); // 不同行的数量int c = countDistinct(cols); // 不同列的数量// 计算结果:总覆盖的格子数// (N * (r + c)) 表示所有被覆盖的行和列的格子数// 减去 (r * c),因为行列交叉的格子会被重复计算long result = (long) N * (r + c) - (long) r * c;// 输出结果System.out.println(result);}/*** 统计数组中不同元素的数量* @param array 已排序的数组* @return 不同元素的数量*/private static int countDistinct(int[] array) {if (array.length == 0)return 0; // 如果数组为空,返回 0int count = 1; // 至少有一个不同的元素for (int i = 1; i < array.length; i++) {// 如果当前元素与前一个元素不同,计数加一if (array[i] != array[i - 1]) {count++;}}return count; // 返回不同元素的数量}
}

P2638 安全系统

解题思路

1. 核心功能

代码的核心是计算组合数(即数学中的 C(n, r)),并将结果进行某种组合运算后输出。组合数的公式为:C(n, r) = \frac{n!}{r! \cdot (n - r)!}

由于可能涉及非常大的数,代码使用了 Java 的 BigInteger 类来处理大数运算。


2. 代码结构

func 方法
  • 该方法用于计算组合数 C(n, r)
  • 通过迭代的方式计算组合数,避免直接计算阶乘(因为阶乘增长非常快,容易导致性能问题或溢出)。
  • 具体实现:
    • 使用一个循环从 1 到 r,逐步计算组合数的分子和分母。
    • 分子:n * (n - 1) * ... * (n - r + 1)
    • 分母:r!
    • 每一步都用 BigInteger 的 multiply 和 divide 方法进行计算。
main 方法
  • 主方法负责读取输入、调用计算方法并输出结果。
  • 输入:
    • 从控制台读取三个 BigInteger 类型的数:n、a 和 b。
  • 计算:
    • 调用 func 方法计算两个组合数:
      • func(n, a + n)
      • func(n, b + n)
    • 将两个组合数的结果相乘。
  • 输出:
    • 使用 write 方法输出最终结果。
import java.math.BigInteger;
import java.util.Scanner;public class Main {// 输出 BigInteger 类型的结果public static void write(BigInteger x) {System.out.print(x);}// 计算组合数public static BigInteger func(BigInteger r, BigInteger n) {BigInteger ans = BigInteger.ONE;// 计算组合数的公式 C(n, r) = n! / (r! * (n - r)!)// 这里使用了 BigInteger 的方法来处理大数for (BigInteger i = BigInteger.ONE; i.compareTo(r) <= 0; i = i.add(BigInteger.ONE)) {ans = ans.multiply(n.subtract(i).add(BigInteger.ONE));ans = ans.divide(i);}return ans;}public static void main(String[] args) {Scanner input = new Scanner(System.in);BigInteger n = input.nextBigInteger();BigInteger a = input.nextBigInteger();BigInteger b = input.nextBigInteger();input.close();// 代入公式计算并输出结果write(func(n, a.add(n)).multiply(func(n, b.add(n))));}
}

P1246 编码

解题思路

  1. 输入验证:检查输入字符串是否由小写字母组成,并且每个字符严格递增。

  2. 计算前缀和:统计所有比当前单词长度短的合法单词数目之和。

  3. 计算当前长度内的位置:使用组合数学的方法计算当前单词在其长度内的位置。

  4. 结果输出:将前缀和与当前长度内的位置相加得到最终编码。

import java.io.*;public class Main {public static void main(String[] args) throws IOException {// 使用 BufferedReader 读取输入BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String s = br.readLine().trim(); // 读取并去除首尾空格int len = s.length(); // 获取输入字符串的长度// 检查字符串长度是否符合要求(1 <= len <= 6)if (len < 1 || len > 6) {System.out.println(0); // 长度不合法,输出 0return;}int[] chars = new int[len]; // 用于存储字符对应的字母序号for (int i = 0; i < len; i++) {char c = s.charAt(i); // 获取字符串中的每个字符// 检查字符是否为小写字母if (c < 'a' || c > 'z') {System.out.println(0); // 非法字符,输出 0return;}chars[i] = c - 'a' + 1; // 将字符转换为字母序号(a=1, b=2, ..., z=26)}// 检查字符是否按严格递增顺序排列for (int i = 0; i < len - 1; i++) {if (chars[i] >= chars[i + 1]) {System.out.println(0); // 非递增,输出 0return;}}int m = len; // 字符串长度long sum = 0; // 用于存储比当前长度短的所有合法字符串的数量// 计算比当前长度短的所有合法字符串数量for (int i = 1; i < m; i++) {sum += comb(26, i); // 从 26 个字母中选 i 个的组合数}long pos = 0; // 当前字符串在所有合法字符串中的相对位置int prev = 0; // 上一个字符的字母序号// 计算当前字符串的相对位置for (int i = 0; i < m; i++) {int current = chars[i]; // 当前字符的字母序号int start = prev + 1; // 起始字母序号int end = current - 1; // 结束字母序号// 遍历从 start 到 end 的所有可能字符for (int j = start; j <= end; j++) {int remain = m - i - 1; // 剩余未处理的字符数pos += comb(26 - j, remain); // 计算剩余字符的组合数}prev = current; // 更新上一个字符的字母序号}pos += 1; // 加上当前字符串本身的位置// 输出结果:比当前字符串小的所有合法字符串数量 + 当前字符串的位置System.out.println(sum + pos);}// 计算组合数 C(n, k)private static int comb(int n, int k) {if (k < 0 || k > n) // 如果 k 不合法,返回 0return 0;if (k == 0 || k == n) // 如果 k 为 0 或 n,返回 1return 1;if (k > n / 2) // 优化计算,C(n, k) = C(n, n-k)k = n - k;int result = 1; // 存储结果for (int i = 1; i <= k; i++) {result = result * (n - k + i) / i; // 使用公式计算组合数}return result;}
}

P2926 [USACO08DEC] Patting Heads S

解题思路

  1. 内存优化策略

    • 使用 HashMap 替代大数组:当数值范围较大时(如最大值为1e9),传统数组会占用过多内存。哈希表只存储实际存在的数值,显著减少内存消耗。

    • 按需计算:仅处理实际存在的数值,避免遍历整个数值范围。

  2. 核心算法逻辑

    • 因数替代倍数:原题要求统计数值的倍数,但优化后改为统计因数。因为当数值范围很大时,因数的数量远小于倍数的数量。

    • 预处理机制:预先计算每个数值的拍打次数并存储,后续查询时间复杂度降为O(1)。

  3. 关键操作说明

    • 因数生成:通过遍历到\sqrt{n}来高效获取所有因数,时间复杂度为O(\sqrt{n})

    • 拍打次数计算:对每个数值的因数集合,累加这些因数在输入中的出现次数总和。

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int N = input.nextInt();        // 读取牛的总数int[] A = new int[N];           // 存储每头牛的数值Map<Integer, Integer> countMap = new HashMap<>(); // 统计数值出现次数// 统计每个数的出现次数for (int i = 0; i < N; i++) {A[i] = input.nextInt();// 使用哈希表记录数值出现次数(自动处理稀疏数据)countMap.put(A[i], countMap.getOrDefault(A[i], 0) + 1);}// 预处理每个数值的拍打次数Map<Integer, Integer> patsMap = new HashMap<>(); // 存储数值对应的拍打总次数for (int num : countMap.keySet()) { // 只处理实际存在的数值int sum = 0;// 获取当前数值的所有因数(包括1和自身)List<Integer> divisors = getDivisors(num);// 累加所有因数的出现次数for (int d : divisors) {sum += countMap.getOrDefault(d, 0);}patsMap.put(num, sum); // 存储计算结果}// 输出结果(需减去自身的一次计数)for (int x : A) {System.out.println(patsMap.get(x) - 1); }input.close();}// 生成一个数的所有因数private static List<Integer> getDivisors(int n) {List<Integer> divisors = new ArrayList<>();// 遍历到sqrt(n)以优化效率for (int i = 1; i <= Math.sqrt(n); i++) {if (n % i == 0) {divisors.add(i);          // 添加较小因数int other = n / i;        // 计算对应较大因数if (other != i) {         // 避免平方数重复添加divisors.add(other);}}}return divisors;}
}

P3383 【模板】线性筛素数

解题思路

  1. 线性筛法

    • 使用 isComposite 数组标记非素数。
    • 通过 primes 列表存储所有素数。
    • 保证每个数只被其最小的素因子标记一次,时间复杂度为 $O(n)$
  2. 查询处理

    • 直接通过 primes.get(k - 1) 获取第 $k$ 小的素数
import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));// 读取 n 和 qString[] firstLine = br.readLine().split(" ");int n = Integer.parseInt(firstLine[0]);int q = Integer.parseInt(firstLine[1]);// 线性筛法求素数List<Integer> primes = new ArrayList<>();boolean[] isComposite = new boolean[n + 1];for (int i = 2; i <= n; i++) {if (!isComposite[i]) {primes.add(i);}for (int prime : primes) {if (i * prime > n) break;isComposite[i * prime] = true;if (i % prime == 0) break;}}// 处理查询for (int i = 0; i < q; i++) {int k = Integer.parseInt(br.readLine());pw.println(primes.get(k - 1)); // 第 k 小的素数}pw.flush();}
}

P1835 素数密度

解题思路

  1. 埃拉托色尼筛法

    • 先标记区间 [l, r] 中所有数为素数。
    • 从小于等于 sqrt(r) 的所有素数开始,将它们的倍数标记为非素数。
    • 通过计算起始位置 start,避免从 1 开始筛选,直接筛选区间内的数。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);long l = input.nextLong();long r = input.nextLong();input.close();System.out.println(func(l, r));}public static int func(long l, long r) {// 使用埃拉托色尼筛法优化return countPrimesInRange(l, r);}public static int countPrimesInRange(long l, long r) {// 标记区间 [l, r] 中的数是否为素数boolean[] isPrime = new boolean[(int) (r - l + 1)];Arrays.fill(isPrime, true);// 从 2 开始筛选素数for (long i = 2; i * i <= r; i++) {long start = Math.max(i * i, (l + i - 1) / i * i); // 找到区间内第一个 i 的倍数for (long j = start; j <= r; j += i) {isPrime[(int) (j - l)] = false;}}// 特殊处理 1 不是素数if (l == 1) {isPrime[0] = false;}// 统计素数个数int count = 0;for (boolean prime : isPrime) {if (prime) {count++;}}return count;}
}

P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题 

解题思路

  1. 理解条件

    • $P$$Q$ 的最大公约数是 $x_0$
    • $P$$Q$ 的最小公倍数是 $y_0$
    • 根据数学性质,$P \times Q = \text{gcd}(P, Q) \times \text{lcm}(P, Q)$,因此 $P \times Q = x_0 \times y_0$
  2. 优化计算

    • $z = y_0 / x_0$z 必须是整数。
    • 我们需要找到所有的正整数对 $(a, b)$,使得 $a \times b = z$$\text{gcd}(a, b) = 1$
    • 对于每个这样的 $(a, b)$,我们可以构造 $P = a \times x_0$$Q = b \times x_0$
  3. 实现代码

    • 遍历 $z$ 的所有因子,检查每对因子是否满足 $\text{gcd}(a, b) = 1$
    • 统计满足条件的因子对数量。

注意事项:

  1. 输入检查

    • 如果 $y_0$ 不是 $x_0$ 的倍数,则直接输出 0,因为无法满足条件。
    • 如果$x_0 = y_0$,直接返回1,两个数相等时只有一个结果就是它们本身。
  2. 因子遍历

    • 遍历 $z$ 的所有因子对 $(a, b)$,并检查 $\text{gcd}(a, b) = 1$
    • 每找到一个因子对 $(a, b)$,计数加 2,因为 $(a, b)$$(b, a)$ 都是有效解。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int x0 = input.nextInt();int y0 = input.nextInt();input.close();// 如果 y0 不是 x0 的倍数,则无解if (y0 % x0 != 0) {System.out.println(0);return;}if (x0 == y0) {System.out.println(1);return;}int z = y0 / x0; // z = y0 / x0int count = 0;// 遍历 z 的所有因子for (int a = 1; a * a <= z; a++) {if (z % a == 0) {int b = z / a; // 因子对 (a, b)// 检查 gcd(a, b) 是否为 1if (gcd(a, b) == 1) {count += 2; // (a, b) 和 (b, a) 都满足条件}}}System.out.println(count);}// 辗转相除法计算 gcdprivate static int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;}
}

P1072 [NOIP 2009 提高组] Hankson 的趣味题

解题思路

  1. 枚举 $k$

    • $k$ 必须满足 $k \cdot a_1 \mid b_1$,因此 $k$ 的范围是 $b_1 / a_1$ 的所有因子。
  2. 验证条件

    • 对于每个 $k$,验证:
      • $\text{gcd}(k \cdot a_1, a_0) = a_1$
      • $\text{lcm}(k \cdot a_1, b_0) = b_1$
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt(); // 读取测试组数StringBuilder result = new StringBuilder();while (n-- > 0) {long a0 = input.nextLong();long a1 = input.nextLong();long b0 = input.nextLong();long b1 = input.nextLong();// 如果 a1 不是 a0 的因子,或者 b1 不是 b0 的倍数,则无解if (a0 % a1 != 0 || b1 % b0 != 0) {result.append(0).append("\n");continue;}// 枚举 k 的所有可能值long xBase = a1; // x = k * a1long limit = b1 / xBase; // k 的最大值int count = 0;for (long k = 1; k * k <= limit; k++) {if (limit % k == 0) {// 检查两个因子 k 和 limit / kif (isValid(k, xBase, a0, b0, b1)) count++;if (k != limit / k && isValid(limit / k, xBase, a0, b0, b1)) count++;}}result.append(count).append("\n");}input.close();System.out.print(result);}// 检查 k 是否满足条件private static boolean isValid(long k, long xBase, long a0, long b0, long b1) {long x = k * xBase;return gcd(x, a0) == xBase && lcm(x, b0) == b1;}// 辗转相除法计算 gcdprivate static long gcd(long a, long b) {while (b != 0) {long temp = b;b = a % b;a = temp;}return a;}// 计算 lcmprivate static long lcm(long a, long b) {return a / gcd(a, b) * b;}
}

P1069 [NOIP 2009 普及组] 细胞分裂

解题思路

  1. 输入处理:读取细胞种数、试管参数和每个细胞的分裂数。

  2. 特殊情况处理:如果m_1为1,直接输出0,因为任何细胞都能立即满足条件。

  3. 质因数分解:将m_1分解质因数,并计算其在M = m_1^{m_2}中的指数。

  4. 细胞有效性检查:对于每个细胞的分裂数,检查是否包含M的所有质因数,并计算每个质因数的指数。

  5. 时间计算:针对每个有效细胞,计算满足条件所需的最长时间,并更新全局最短时间。

  6. 结果输出:根据是否存在有效细胞输出最短时间或-1。

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int N = input.nextInt();int m1 = input.nextInt();int m2 = input.nextInt();int[] S = new int[N];for (int i = 0; i < N; i++) {S[i] = input.nextInt();}// 处理m1=1的特殊情况,任何情况都能在0秒完成if (m1 == 1) {System.out.println(0);return;}// 分解m1的质因数Map<Integer, Integer> m1Factors = primeFactors(m1);// 计算M的质因数分解(每个指数乘以m2)Map<Integer, Integer> mFactors = new HashMap<>();for (Map.Entry<Integer, Integer> entry : m1Factors.entrySet()) {mFactors.put(entry.getKey(), entry.getValue() * m2);}int minTime = Integer.MAX_VALUE;for (int s : S) {boolean valid = true;Map<Integer, Integer> sFactors = new HashMap<>();// 检查s是否包含所有M的质因数for (int p : mFactors.keySet()) {if (s % p != 0) {valid = false;break;}// 计算s中质因数p的指数int e = 0;int temp = s;while (temp % p == 0) {e++;temp /= p;}sFactors.put(p, e);}if (!valid)continue;// 计算当前s所需的最大时间int currentMax = 0;for (Map.Entry<Integer, Integer> entry : mFactors.entrySet()) {int p = entry.getKey();int requiredExp = entry.getValue(); // M中p的指数int sExp = sFactors.get(p); // s中p的指数// 向上取整计算所需时间int t = (requiredExp + sExp - 1) / sExp;if (t > currentMax) {currentMax = t;}}// 更新全局最小时间if (currentMax < minTime) {minTime = currentMax;}}System.out.println(minTime == Integer.MAX_VALUE ? -1 : minTime);input.close();}// 质因数分解方法private static Map<Integer, Integer> primeFactors(int n) {Map<Integer, Integer> factors = new HashMap<>();if (n == 1)return factors;// 处理2的因数while (n % 2 == 0) {factors.put(2, factors.getOrDefault(2, 0) + 1);n /= 2;}// 处理奇数因数for (int i = 3; i * i <= n; i += 2) {while (n % i == 0) {factors.put(i, factors.getOrDefault(i, 0) + 1);n /= i;}}// 处理剩余的质因数if (n > 2) {factors.put(n, 1);}return factors;}
}

P1572 计算分数

解题思路

  1. 解析输入
    • 将输入的分数表达式拆分为多个分数项,每个分数项形如 a/b
    • 处理分数项之间的运算符(+ 或 -)。
  2. 分数运算
    • 使用分数的加减法公式:
      [ \frac{a}{b} + \frac{c}{d} = \frac{a \cdot d + c \cdot b}{b \cdot d} ] [ \frac{a}{b} - \frac{c}{d} = \frac{a \cdot d - c \cdot b}{b \cdot d} ]
    • 每次计算后化简分数(求最大公约数 GCD)。
  3. 化简分数
    • 使用欧几里得算法求最大公约数(GCD),将分子和分母同时除以 GCD。
  4. 输出结果
    • 如果分母为 1,则输出整数。
    • 否则输出最简分数。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);String expression = input.nextLine();input.close();// 初始化分子和分母int numerator = 0; // 当前分子int denominator = 1; // 当前分母// 正则表达式匹配分数项String[] terms = expression.split("(?=[+-])"); // 按 `+` 或 `-` 分割for (String term : terms) {// 分割分子和分母String[] fraction = term.split("/");int num = Integer.parseInt(fraction[0]); // 分子int den = Integer.parseInt(fraction[1]); // 分母// 计算通分后的分子和分母numerator = numerator * den + num * denominator;denominator *= den;// 化简分数int gcd = gcd(Math.abs(numerator), denominator);numerator /= gcd;denominator /= gcd;}// 输出结果if (denominator == 1) {System.out.println(numerator); // 如果分母为 1,输出整数} else {System.out.println(numerator + "/" + denominator); // 输出最简分数}}// 求最大公约数(GCD)private static int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
}

P4057 [Code+#1] 晨跑

解题思路

  1. 问题分析
    • 三位同学的晨跑周期分别为 ab 和 c
    • 他们在第 0 天相遇,下一次相遇的天数是 ab 和 c 的最小公倍数(LCM)。
  2. 计算最小公倍数(LCM)
    • 最小公倍数公式:
      [ \text{LCM}(x, y) = \frac{x \cdot y}{\text{GCD}(x, y)} ]
    • 其中 GCD 是最大公约数,可以使用欧几里得算法计算。
  3. 扩展到三个数
    • 先计算两个数的 LCM,然后将结果与第三个数计算 LCM。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 读取输入long a = input.nextLong();long b = input.nextLong();long c = input.nextLong();input.close();// 计算三者的最小公倍数long lcmAB = lcm(a, b); // a 和 b 的最小公倍数long lcmABC = lcm(lcmAB, c); // lcmAB 和 c 的最小公倍数// 输出结果System.out.println(lcmABC);}// 求最大公约数(GCD)private static long gcd(long x, long y) {return y == 0 ? x : gcd(y, x % y);}// 求最小公倍数(LCM)private static long lcm(long x, long y) {return x / gcd(x, y) * y; // 防止溢出,先除后乘}
}

P1414 又是毕业季II

解题思路

  1. 输入处理与频率统计
    读取输入数据并统计每个数出现的次数,记录在freq数组中,同时确定最大值max_x

  2. 因数统计
    对每个存在的数生成其所有因数,并统计每个因数的倍数总次数cnt[d]。例如,若数x出现freq[x]次,则其所有因数d对应的cnt[d]增加freq[x]

  3. 因数降序处理
    将所有可能的因数按降序排列,确保后续处理时优先考虑较大的因数。

  4. 填充答案数组
    遍历降序后的因数列表,根据每个因数d的倍数总数cnt[d],更新答案数组ans。对于每个d,若其倍数总数c大于当前已覆盖的最大值max_so_far,则填充ans数组的未覆盖区间,确保每个k取到最大可能的d

  5. 输出结果
    按顺序输出ans[1]ans[n],即每个k对应的最大公约数。

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt();int[] a = new int[n];int max_x = 0;int[] freq = new int[1000002]; // 存储每个数的出现次数,最大1e6+1// 读取输入并统计频率for (int i = 0; i < n; i++) {a[i] = input.nextInt();freq[a[i]]++;if (a[i] > max_x) {max_x = a[i];}}int[] cnt = new int[max_x + 2]; // cnt[d]表示d的倍数的总个数Set<Integer> divisorsSet = new HashSet<>();// 统计所有因数及其出现次数for (int x = 1; x <= max_x; x++) {if (freq[x] == 0)continue;List<Integer> divisors = getDivisors(x);for (int d : divisors) {cnt[d] += freq[x];divisorsSet.add(d);}}// 将因数按降序排列List<Integer> divisorsList = new ArrayList<>(divisorsSet);Collections.sort(divisorsList, Collections.reverseOrder());int[] ans = new int[n + 1]; // ans[k]表示选k人时的最大gcdint max_so_far = 0;// 填充答案数组for (int d : divisorsList) {int c = cnt[d];if (c == 0)continue;if (c > max_so_far) {int start = max_so_far + 1;int end = Math.min(c, n);if (start > end)continue;for (int k = start; k <= end; k++) {ans[k] = d;}max_so_far = end;if (max_so_far == n)break; // 提前终止}}// 输出结果for (int k = 1; k <= n; k++) {System.out.println(ans[k]);}input.close();}// 生成一个数的所有因数private static List<Integer> getDivisors(int x) {List<Integer> divisors = new ArrayList<>();for (int i = 1; i * i <= x; i++) {if (x % i == 0) {divisors.add(i);int other = x / i;if (other != i) {divisors.add(other);}}}return divisors;}
}

P2651 添加括号III

解题思路

  1. 输入处理:使用Scanner读取输入数据,处理多个测试用例。

  2. 特殊情况处理:当分母为1时,直接输出"Yes"。

  3. 质因数分解函数:对给定的数进行质因数分解,返回质因数及其指数的映射。

  4. 统计质因数次数:遍历分子部分的每个数,统计所有质因数的总次数。

  5. 结果判断:检查分母的每个质因数是否在分子中有足够的次数覆盖,若全部满足则输出"Yes",否则输出"No"。

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int t = input.nextInt();while (t-- > 0) {int n = input.nextInt();int[] a = new int[n];for (int i = 0; i < n; i++) {a[i] = input.nextInt();}if (n < 2) {System.out.println("Yes");continue;}int a2 = a[1];if (a2 == 1) {System.out.println("Yes");continue;}// 计算第二个元素的质因数分解结果Map<Integer, Integer> m2Factors = primeFactors(a2);// 如果没有质因数,输出yes跳到下一个元素if (m2Factors.isEmpty()) {System.out.println("Yes");continue;}int a1 = a[0];// 计算第一个元素的质因数分解结果Map<Integer, Integer> total = primeFactors(a1);// 从数组的第三个元素开始,依次计算每个元素的质因数分解结果for (int i = 2; i < n; i++) {int x = a[i];// 计算当前元素的质因数分解结果Map<Integer, Integer> xFactors = primeFactors(x);// 遍历当前元素的质因数分解结果for (Map.Entry<Integer, Integer> entry : xFactors.entrySet()) {// 获取质因数int p = entry.getKey();// 获取该质因数的个数int cnt = entry.getValue();// 将该质因数的个数累加到 total 中total.put(p, total.getOrDefault(p, 0) + cnt);}}boolean ok = true;// 遍历第二个元素的质因数分解结果for (Map.Entry<Integer, Integer> entry : m2Factors.entrySet()) {int p = entry.getKey();int required = entry.getValue();int actual = total.getOrDefault(p, 0);if (actual < required) {ok = false;break;}}System.out.println(ok ? "Yes" : "No");}input.close();}// 计算一个数的质因数分解结果private static Map<Integer, Integer> primeFactors(int x) {// 用于存储质因数及其个数的映射Map<Integer, Integer> factors = new HashMap<>();if (x == 1) {return factors;}// 处理 2 这个质因数while (x % 2 == 0) {factors.put(2, factors.getOrDefault(2, 0) + 1);x /= 2;}// 从 3 开始,以 2 为步长遍历奇数,直到 sqrt(x)for (int i = 3; i <= Math.sqrt(x); i += 2) {while (x % i == 0) {// 更新当前质因数的个数factors.put(i, factors.getOrDefault(i, 0) + 1);// 将 x 除以当前质因数x /= i;}}// 如果 x 大于 2,说明 x 本身是一个质数,将其作为质因数添加到映射中if (x > 2) {factors.put(x, 1);}return factors;}
}

P2660 zzc 种田

解题思路

  1. 输入处理:使用 Scanner 读取输入的 x 和 y 值。

  2. 计算最大公约数:通过欧几里得算法计算 x 和 y 的最大公约数。

  3. 公式计算:代入公式 4×(x+y−gcd(x,y))4×(x+y−gcd(x,y)) 得到最小体力值,并输出结果。

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);long x = input.nextLong();long y = input.nextLong();long gcd = gcd(x, y);System.out.println(4 * (x + y - gcd));input.close();}private static long gcd(long a, long b) {while (b != 0) {long temp = b;b = a % b;a = temp;}return a;}
}

P3601 签到题

解题思路

  1. 质因数分解与欧拉函数:欧拉函数 \varphi (x) 表示与 x 互质的数的个数。通过分解 x 的质因数并应用欧拉函数公式 \varphi (x) =x*\sqcap (1-\frac{1}{p}),其中 p 是 x 的质因数,我们可以高效计算\varphi (x)

  2. 筛法生成质数:使用埃拉托斯特尼筛法生成所有小于等于 sqrt(r) 的质数,用于后续处理。

  3. 区间处理:对于每个质数 p,处理区间中的每个 p 的倍数,计算对应的欧拉函数值。

  4. 剩余质数处理:处理区间中剩余的大质数,确保每个数的欧拉函数正确计算。

import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);long l = input.nextLong();long r = input.nextLong();int len = (int) (r - l + 1);long[] phi = new long[len];long[] rem = new long[len];for (int i = 0; i < len; i++) {long x = l + i;phi[i] = x;rem[i] = x;}int maxPrime = (int) Math.sqrt(r) + 1;boolean[] isPrime = new boolean[maxPrime + 1];Arrays.fill(isPrime, true);     // 假设所有数都是素数isPrime[0] = isPrime[1] = false;    // 0 和 1 不是素数// 使用埃拉托色尼筛法标记非素数for (int i = 2; i * i <= maxPrime; i++) {if (isPrime[i]) {for (int j = i * i; j <= maxPrime; j += i) {isPrime[j] = false;     // 标记为非素数}}}List<Integer> primes = new ArrayList<>();for (int i = 2; i <= maxPrime; i++) {if (isPrime[i]) {primes.add(i);}}// 遍历每个素数,对区间 [l, r] 内的数进行处理for (int p : primes) {// 找到区间内第一个是 p 的倍数的数long start = ((l + p - 1) / p) * p;if (start > r) {continue; // 如果起始点超出区间,跳过}// 遍历区间内所有是 p 的倍数的数for (long x = start; x <= r; x += p) {int i = (int) (x - l); // 计算当前数在数组中的索引if (rem[i] < p) {continue; // 如果余数小于当前素数,跳过}// 如果当前数能被 p 整除,更新 phi 和 remif (rem[i] % p == 0) {phi[i] = phi[i] / p * (p - 1); // 更新欧拉函数值while (rem[i] % p == 0) {rem[i] /= p;}}}}// 处理区间内剩余的数(大于 sqrt(r) 的素因子)for (int i = 0; i < len; i++) {if (rem[i] > 1) {   // 如果余数大于 1,说明是一个素数phi[i] = phi[i] / rem[i] * (rem[i] - 1);    // 更新欧拉函数值}}long sum = 0;long mod = 666623333;for (int i = 0; i < len; i++) {long current = ((l + i) - phi[i]) % mod;    // 计算当前数的结果sum = (sum + current) % mod;    // 累加结果}System.out.println(sum);input.close();}
}

P1403 [AHOI2005] 约数研究

解题思路

  1. 约数个数的性质

    • 对于一个数 i,它的约数可以通过遍历 1 到 sqrt(i) 来找到。
    • 但是直接计算每个数的约数个数会导致时间复杂度为 O(n * \sqrt n),对于 n 最大为 10^6 的情况,这种方法会超时。
  2. 优化方法

    • 利用约数的性质,反向思考:对于每个数 j,它会作为约数出现在 j, 2j, 3j, ... 中。
    • 因此,可以通过遍历每个数 j,将其作为约数累加到所有的倍数上。
    • 这种方法的时间复杂度为 O(n),适合 n 较大的情况。
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt();input.close();System.out.println(sumOfDivisors(n));}// 计算从 1 到 n 的所有正整数的约数个数之和public static long sumOfDivisors(int n) {long sum = 0;for (int i = 1; i <= n; i++) {sum += (long) (n / i);}return sum;}
}

P1593 因子和

解题思路

  1. ​质因数分解​​:

    • 将输入的数 a 分解为质因数的乘积形式,例如 a=p_1^{e_1}\times p_2^{e_2}\times \dots \times p_n^{e_n}
    • 对于每个质因数 p_i,在 a^b 中的指数变为 e_i\times b
  2. ​等比数列求和​​:

    • 对于每个质因数 p 和其指数 e×b,计算等比数列 1+p+p^2+\dots+p^e 的和。
    • 使用公式 (p^{e+1}-1)/(p-1) 计算和,但需要注意模运算中的除法处理。
  3. ​模逆元计算​​:

    • 在模运算中,除法转换为乘以模逆元。利用费马小定理(因为 9901 是质数),模逆元可通过快速幂计算。
  4. ​特殊情况处理​​:

    • 当 p≡1 mod 9901 时,分母为 0,此时等比数列的和简化为 e+1。
    • 处理 a=0 或 b=0 的边界情况。
import java.util.*;public class Main {static final int MOD = 9901;public static void main(String[] args) {Scanner input = new Scanner(System.in);int a = input.nextInt();int b = input.nextInt();input.close();System.out.println(factorSum(a, b));}// 计算a^b的因子和,对MOD取模public static int factorSum(int a, int b) {if (b == 0) return 1; // a^0 = 1,因子和为1if (a == 0) return 0; // 0^b = 0(b>0),因子和为0Map<Integer, Integer> primeFactors = primeFactorize(a);int result = 1;for (Map.Entry<Integer, Integer> entry : primeFactors.entrySet()) {int p = entry.getKey();int e = entry.getValue() * b;result = (result * geometricSum(p, e)) % MOD;}return (result % MOD + MOD) % MOD; // 确保非负}// 质因数分解public static Map<Integer, Integer> primeFactorize(int n) {Map<Integer, Integer> factors = new HashMap<>();// 处理偶数if (n % 2 == 0) {int count = 0;while (n % 2 == 0) {count++;n /= 2;}factors.put(2, count);}// 处理奇数for (int i = 3; (long) i * i <= n; i += 2) {if (n % i == 0) {int count = 0;while (n % i == 0) {count++;n /= i;}factors.put(i, count);}}// 处理剩余的质数if (n > 1) {factors.put(n, 1);}return factors;}// 计算等比数列和 (1 + p + p^2 + ... + p^e) % MODpublic static int geometricSum(int p, int e) {if (e == 0) return 1; // 指数为0时和为1long pMod = p % MOD;if (pMod == 1) { // 当p ≡ 1 (mod MOD)时,和为e+1return (e + 1) % MOD;}// 计算 (p^(e+1) - 1) / (p-1) mod MODlong numerator = (modPow(p, e + 1, MOD) - 1 + MOD) % MOD; // 分子,处理负数int denominator = modInverse((int) ((p - 1) % MOD), MOD); // 分母的逆元return (int) ((numerator * denominator) % MOD);}// 快速幂计算 (base^exp) % modpublic static int modPow(int base, int exp, int mod) {long result = 1;long x = base % mod;while (exp > 0) {if ((exp & 1) == 1) {result = (result * x) % mod;}x = (x * x) % mod;exp >>= 1;}return (int) result;}// 费马小定理求逆元:a^(mod-2) % mod(要求mod为质数)public static int modInverse(int a, int mod) {return modPow(a, mod - 2, mod);}
}
http://www.dtcms.com/wzjs/265989.html

相关文章:

  • 俄罗斯b2b常用网站宜昌seo
  • 手机网站js触屏滑动图片特效友情链接作用
  • 河南郑州汽车网网站建设百度手机关键词排名工具
  • 政府网站建设 问题如何在百度发布文章
  • 网站建设推荐中企动力网站建站模板
  • 广州比较好的网站建设公司百度域名查询
  • 网站信息化建设具体内容廊坊关键词快速排名
  • 电影网站做淘宝联盟外包公司和劳务派遣的区别
  • 网站后台的关键词全网网络营销推广
  • 网站开发讲座近期发生的新闻
  • 用python语言做网站今日资讯最新消息
  • 做网站如何赚流量钱安卓优化神器
  • 网站上如何设置行间距广州网站推广软件
  • 怎么做网站流量北京网站建设公司哪家好
  • 建设网站筛选网站供应商营销型制作网站公司
  • wordpress css文件路径保定seo推广公司
  • 太原0元网站建设seo推广怎么学
  • 远离有害不良网站应该怎么做百度怎么做自己的网页
  • 政府网站建设 费用站长之家官网登录入口
  • 北京建站公司哪家好小广告多的网站
  • 重庆手机软件开发seo百度快速排名软件
  • wordpress 焦点图大小长春网站快速优化排名
  • 上海做网站那家公司好北京seo优化
  • 网站建设方案书 下载哪个网站学seo是免费的
  • 什么网站服务器好深圳网站提升排名
  • 个人网站静态网页模板seo关键词优化举例
  • 武汉哪家做营销型网站好市场调研报告怎么做
  • 湖北交投建设集团有限公司网站广州网站建设正规公司
  • 怎么自建一个网站网页设计需要学什么
  • seo网站上线前分析bt种子磁力搜索