方程的解

方程的解

佳佳碰到了一个难题,请你来帮忙解决。

对于不定方程 $a_1 + a_2+ \ldots + a_{k−1} + a_k = g(x)$,其中 $k \geq 1$ 且 $k \in N^{*}$,$x$ 是正整数,$g(x) = x^{x} \bmod 1000$(即 $x^{x}$ 除以 $1000$ 的余数),$x,k$ 是给定的数。

我们要求的是这个不定方程的正整数解组数。

举例来说,当 $k=3,x=2$ 时,方程的解分别为:

$$\begin{cases} a_1 = 1 \\ a_2 = 1 \\ a_3 = 2 \end{cases} \ \ \begin{cases} a_1 = 1 \\ a_2 = 2 \\ a_3 = 1 \end{cases} \ \ \begin{cases} a_1 = 2 \\ a_2 = 1 \\ a_3 = 1 \end{cases}$$

输入格式

有且只有一行,为用空格隔开的两个正整数,依次为 $k,x$。

输出格式

有且只有一行,为方程的正整数解组数。

数据范围

$1 \leq k \leq 100$,
$1 \leq x < 2^{31}$,
$k \leq g(x)$

输入样例:

3 2

输出样例:

3

 

解题思路

  假设$n = x^x \bmod 1000$,这个可以用快速幂来求。因此问题就变成了求满足$a_1 + a_2 + \cdots + a_k = n$的正整数解的数量。这是一个经典的问题,可以转换成小球和隔板的问题,俗称隔板法

  把$n$看成$n$个小球,现在有$k$个未知数,看成是$k-1$个板子,把这$k-1$个板子插到$n-1$个空隙里面,一共把小球分成$k$组,每一种摆法都对应方程的一组解(正整数解)。因此解的方案数就等于放隔板的方案数,因此答案就是$C_{n-1}^{k-1}$。

  由于这题没有取模,因此需要写高精度。为了方便这里用递推的方法来求组合数,其中$C_{1000}^{100}$的数位有$150$多位,因此计算量为$1000 \times 100 \times 150 \approx 10^7$级别。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1010, M = 110;
 5 
 6 vector<int> c[N][M];
 7 
 8 int qmi(int a, int k, int p) {
 9     int ret = 1;
10     while (k) {
11         if (k & 1) ret = ret * a % p;
12         a = a * a % p;
13         k >>= 1;
14     }
15     return ret;
16 }
17 
18 void add(vector<int> &c, vector<int> &a, vector<int> &b) {
19     int t = 0;
20     for (int i = 0; i < a.size() || i < b.size(); i++) {
21         if (i < a.size()) t += a[i];
22         if (i < b.size()) t += b[i];
23         c.push_back(t % 10);
24         t /= 10;
25     }
26     if (t) c.push_back(t);
27 }
28 
29 int main() {
30     int n, m, x;
31     scanf("%d %d", &m, &x);
32     n = qmi(x % 1000, x, 1000);
33     for (int i = 0; i < n; i++) {
34         for (int j = 0; j <= i && j < m; j++) {
35             if (j == 0) c[i][j].push_back(1);   // c[i][0] = 1
36             else add(c[i][j], c[i - 1][j], c[i - 1][j - 1]);    // c[i][j] = c[i - 1][j] + c[i - 1][j - 1]
37         }
38     }
39     for (int i = c[n - 1][m - 1].size() - 1; i >= 0; i--) {
40         printf("%d", c[n - 1][m - 1][i]);
41     }
42     
43     return 0;
44 }

 

参考资料

  AcWing 1308. 方程的解(算法提高课):https://www.acwing.com/video/718/

posted @ 2023-02-02 12:22  onlyblues  阅读(61)  评论(0编辑  收藏  举报
Web Analytics