2019拼多多学霸批第二批笔试题第三题C++解法及解析。

参考:2019 拼多多校招第三题sum 服务端研发工程师

题目描述

给定两个正整数N和S,你需要找出所有的长度为N的正整数数列中,满足单调递增以及总和为S的数列有多少个。

输入描述

共一行,两个整数N和S(1 < N, S < 1000)。

输出描述

一个整数,为满足条件的数列个数对100000007取模的结果。

分析

  • 最佳解法:动态规划,这里用vec[n][s]表示和为s长度为n的序列个数。
  • 状态转换方程:vec[n][s] = vec[n][s-n] + vec[n-1][s-n]
  • 解释:
    • vec[n][s-n]:表示和为s-n的长度为n的序列个数(把它们都加上1,便成了开头数字为非1且和为s的长度为n的序列个数);
    • vec[n-1][s-n]:表示开头数字为非1,和为s-n的长度为n-1的序列个数(把它们都加上1,然后在序列开头加入1,便成了开头数字为1且和为s的长度为b的序列个数)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void getCnt(const int& N, const int& S, vector<vector<int> >& vec) {
if (vec[N][S] != 0)
return;

for (int i = 2; i <= N; ++i) {
for (int j = i + 1; j <= S; ++j)
vec[i][j] = (vec[i][j-i] + vec[i-1][j-i]) % 1000000007;
}
}

int main() {
int N, S;

while(cin >> N >> S) {
vector<vector<int> > vec(N + 1, vector<int>(S + 1, 0));
for (int i = 1; i <= S; ++i)
vec[1][i] = 1;

getCnt(N, S, vec);
cout << vec[N][S] % 1000000007 << endl;
}
return 0;
}