计算系数

先导

根据高中的数学知识二项式定理,我们可以得到

\((x+y)^n=C_{n}^0x^ny^0+C_{n-1}^1x^{n-1}y1+...+C_{n}^nx^0y^n\)

我们可以这样理解,比如这样一个式子,\((x+y)^5\)

如果我们要求\(x^3y^2\)的系数,那么我们想象成有\(()()()()()\)个括号连续相乘,为了得到\(x^3y^2\)

我们需要从\(5\)个括号中选出\(3\)个来作为\(x\)相乘的项,即\(C_{5}^3\)\((x)^3\)

另外还剩下两个括号,我们选出\(2\)个括号作为\(y\)相乘的项,即\(C_{2}^2(y)^2\)

最后把这两个分散的项相乘得到\(C_{5}^3(x)^3C_{2}^2(y)^2\)

推广

那么进行推广我们可以得到

\((x+y+z)^n\)如果要求\(x^ay^bz^c\)的系数

还是想象成有\(n\)个括号连续相乘

\(n\)个括号中选出\(a\)个凑成\(x^a\),即\(C_{n}^a(x)^a\)

从剩下的\(n-a\)个括号选出\(b\)个凑出\(y^b\),即\(C_{n-a}^b(y)^b\)

最后从剩下的\(n-a-b\)个括号中选出\(c\)个凑出\(z^c\),即\(C_{n-a-b}^c(z)^c\)

最后的最后把这些分散的项相乘就是最终\(x^ay^bz^c\)的系数

(注意,我这里之所以要把\(x,y,z\)外面带上括号,就是因为某些情况下,\(x\)前面的系数可能不为1,这个时候还要把\(x\)前面的系数也算上)

比如要求\(x^3y^2\)

\((2x+3y)^5=C_{5}^3(2x)^3C_{2}^2(3y)^2\)

有了上面的知识储备,下面的这道题一定就非常简单了

真题

给定一个多项式\((ax+by)^k\),请求出多项式展开后\(x^ny^m\)项的系数。

输入格式

共一行,包含 5 个整数,分别为 \(a,b,k,n,m\),每两个整数之间用一个空格隔开。

输出格式

输出共 1 行,包含一个整数,表示所求的系数,这个系数可能很大,输出对10007 取模后的结果。

数据范围

\(0≤n,m≤k≤1000\)
\(n+m=k\)
\(0≤a,b≤10^6\)

输入样例:

1 1 3 1 2 

输出样例:

3

题解

从连续的\(k\)个括号中选出\(n\)个作为凑成\(x^n\)

\(C_{k}^n(ax)^n\)

从剩下的\(k-n\)个括号中选出\(m\)个凑成\(y^m\)

\(C_{k-n}^{m}(by)^m\)

最后答案\(C_{k}^n(ax)^n\)\(C_{k-n}^{m}(by)^m\)

所以我们的代码只需要处理

\(a^n\)\(b^m\),还有组合数的计算就行

代码

#include <cmath>
#include <iostream>

using namespace std;
const int mod = 10007;
const int N = 1010;
int a, b, k, n, m;
int c[N][N];
void init() {
  for (int i = 0; i <= 1000; i++)
    for (int j = 0; j <= i; j++) {
      if (j == 0)
        c[i][j] = 1;
      else
        c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
    }
}

int qmi(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = (long long)ans * a % mod;
    a = (long long)a * a % mod;
    b >>= 1;
  }
  return ans % mod;
}
int main() {
  init();  //预处理出组合数
  cin >> a >> b >> k >> n >> m;
  cout << (long long)qmi(a, n) * qmi(b, m) * c[k][n] % mod;
  return 0;
}
posted @ 2021-02-10 22:49  邦的轩辕  阅读(524)  评论(0编辑  收藏  举报