2019081001 模拟T1数字| dp | dfs剪枝

数字(number)
背景:
Jkxing 最喜欢数学了
题目:
在一个风和日丽的夜晚,jkxing 正在沉思,正如所有关于历史的书籍中所记载的,
jkxing 灵光一闪,在18 10 秒内在草纸上写下了1 到n 之间的正整数,由于某种机
缘巧合,szy 从阴暗的角落中飘出,打断了jkxing 的冥想。
于是jkxing 如是说:
告诉我,从这些数内选k 个数,使这些数和为s,一共有多少种选法?
( 旁白:0<=n<=50, 0<= k<=n, 0<=s<=2000 )
Szy:打表呀!!!???
Jkxing:如果要求码长小于5K 呢?
于是szy 消失了。
于是这个问题就要由你解决了。
你面临着两个选择,要么像szy 一样消失,要么回答这个问题。
不过请记住,你只有5K 码长。
格式:
输入第一行为n,k,s 表示从1 到n 的正整数内选择k 个数,使其和为s。
结果取模1e9+7
输出一行表示从1 到n 的正整数内选择k 个数,使其和为s 的方案数取模1e9+7
样例输入
9 3 22
样例输出
2
数据范围
对于20%的数据
n<=10 , k<=n , s<= 30
对于100%的数据
0<=n<=50, 0<= k<=n, 0<=s<=2000

题解:

dfs+剪枝 20分

dp 100分

设dp[i][j][k]表示前i个数选j个数和为k的方案数

dp[i][j][k] = dp[i - 1][j - 1][k - i] + dp[i -1][j][k](i选,i不选)

由于每次前i个数的状态都能由前i -1个数的状态转移过来,所以可以用滚动数组减一维

dp[j][k] = dp[j - 1][k - i] + dp[j - 1][k]并将j,k倒着枚举

o(n^3)的复杂度

 

 1 #include<cstdio>
 2 using namespace std;
 3 int dp[55][2005],f[55][2005];
 4 int mod = 1e9 + 7;
 5 int main()
 6 {
 7     freopen("number.in","r",stdin);
 8     freopen("number.out","w",stdout);
 9     int n,kk,s;
10     scanf("%d%d%d",&n,&kk,&s);
11     f[0][0] = 1;
12     for(int i = 1;i <= n;i ++)
13     {
14         for(int j = kk;j > 0;j --)
15         {
16             for(int k = s;k > 0;k --)
17             {
18                 f[j][k] = dp[j][k] + f[j][k];
19                 f[j][k] %= mod;
20                 if(k >= i)
21                 {
22                     dp[j][k] = dp[j - 1][k - i] + f[j - 1][k - i];
23                     dp[j][k] %= mod;
24                 }
25                 else dp[j][k] = 0;
26             }
27         }
28     }
29     printf("%d",(dp[kk][s] + f[kk][s]) % mod);
30     return 0;
31 }
posted @ 2019-11-09 20:02  djfuuxjz  阅读(30)  评论(0编辑  收藏  举报