【ACWing】1308. 方程的解

文章描述了一种处理不定方程a_1+a_2+...+a_k=g(x),其中g(x)=x^xmod1000的问题。通过快速幂计算x^x模1000的结果,然后利用隔板法求解正整数解的个数,使用递推公式进行高精度计算。代码示例展示了如何实现这一过程,时间复杂度为O(logx+k),空间复杂度为O(1)。
摘要由CSDN通过智能技术生成

题目地址:

https://www.acwing.com/problem/content/1310/

佳佳碰到了一个难题,请你来帮忙解决。对于不定方程 a 1 + a 2 + ⋯ + a k − 1 + a k = g ( x ) a_1+a_2+⋯+a_{k−1}+a_k=g(x) a1+a2++ak1+ak=g(x),其中 k ≥ 1 k≥1 k1 k ∈ N + k∈N^+ kN+ x x x是正整数, g ( x ) = x x m o d    1000 g(x)=x^x\mod1000 g(x)=xxmod1000(即 x x x^x xx除以 1000 1000 1000的余数), x , k x,k x,k是给定的数。我们要求的是这个不定方程的正整数解组数。举例来说,当 k = 3 , x = 2 k=3,x=2 k=3,x=2时,方程的解分别为: { a 1 = 1 a 2 = 1 a 3 = 2 \left\{ \begin{array}{l} a_1=1 \\ a_2=1 \\ a_3=2 \\ \end{array} \right. a1=1a2=1a3=2 { a 1 = 1 a 2 = 2 a 3 = 1 \left\{ \begin{array}{l} a_1=1 \\ a_2=2 \\ a_3=1 \\ \end{array} \right. a1=1a2=2a3=1 { a 1 = 2 a 2 = 1 a 3 = 1 \left\{ \begin{array}{l} a_1=2 \\ a_2=1 \\ a_3=1 \\ \end{array} \right. a1=2a2=1a3=1

输入格式:
有且只有一行,为用空格隔开的两个正整数,依次为 k , x k,x k,x

输出格式:
有且只有一行,为方程的正整数解组数。

数据范围:
1 ≤ k ≤ 100 1≤k≤100 1k100
1 ≤ x < 2 31 1≤x<2^{31} 1x<231
k ≤ g ( x ) k≤g(x) kg(x)

先用快速幂求 n = x x m o d    1000 n=x^x\mod 1000 n=xxmod1000,接着问题转化为求 a 1 + . . . + a k = n a_1+...+a_k=n a1+...+ak=n的正整数解的个数,可以用隔板法求出答案为 ( n − 1 k − 1 ) n-1\choose k-1 (k1n1)。组合数有递推公式 ( n k ) = ( n − 1 k − 1 ) + ( n − 1 k ) {n\choose k}={n-1\choose k-1}+{n-1\choose k} (kn)=(k1n1)+(kn1)。令 f [ n ] [ k ] = ( n k ) , k ≤ n f[n][k]={n\choose k}, k\le n f[n][k]=(kn),kn,已知 f [ 0 ] [ 0 ] = 1 f[0][0]=1 f[0][0]=1,一路递推即可。最终答案大概是 ( 1000 100 ) {1000\choose 100} (1001000)这个级别,需要高精度。代码如下:

#include <iostream>
using namespace std;

const int N = 150, mod = 1000;
int k, x;
int f[1000][100][N];

int qmi(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1) res = res * a % mod;
    b >>= 1;
    a = a * a % mod;
  }
  return res;
}

// 高精度 a = b + c
void add(int a[N], int b[N], int c[N]) {
  for (int i = 0, t = 0; i < N; ++i) {
    t += b[i] + c[i];
    a[i] = t % 10;
    t /= 10;
  }
}

int main() {
  scanf("%d%d", &k, &x);
  int n = qmi(x % mod, x);

  for (int i = 0; i < n; ++i) {
    for (int j = 0; j <= i && j < k; ++j) {
      if (!j) f[i][j][0] = 1;
      else add(f[i][j], f[i - 1][j], f[i - 1][j - 1]);
    }
  }

  // 不要打印开头0
  int m = N - 1;
  while (!f[n - 1][k - 1][m]) m--;
  while (m >= 0) printf("%d", f[n - 1][k - 1][m--]);
  puts("");
}

时间复杂度 O ( log ⁡ x + k ) O(\log x+k) O(logx+k),空间 O ( 1 ) O(1) O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值