牛牛在农场饲养了n只奶牛,依次编号为0到n-1, 牛牛的好朋友羊羊帮牛牛照看着农场.有一天羊羊看到农场中逃走了k只奶牛,但是他只会告诉牛牛逃走的k只奶牛的编号之和能被n整除。你现在需要帮牛牛计算有多少种不同的逃走的奶牛群。因为结果可能很大,输出结果对1,000,000,007取模。
例如n = 7 k = 4:
7只奶牛依次编号为0到6, 逃走了4只
编号和为7的有:{0, 1, 2, 4}
编号和为14的有:{0, 3, 5, 6}, {1, 2, 5, 6}, {1, 3, 4, 6},{2, 3, 4, 5}
4只牛的编号和不会大于18,所以输出5.输入描述:
输入包括一行,两个整数n和k(1 ≤ n ≤ 1000),(1 ≤ k ≤ 50),以空格分割。输出描述:
输出一个整数表示题设所求的种数。输入例子:
7 4输出例子:
5
分析:
考虑前 i 头奶牛、所有选取个数情况下的所有余数情况
(此题与另一道砌砖块的题神似:
http://blog.csdn.net/xiaxzhou/article/details/72782299)
- 状态转移方程:
使用dp[i][j][t]表示前
则方案分为两种:选取了第
i
头奶牛和没有选取第
没有选择第 i 头奶牛的方案数:
dp[i−1][j][t]
选择第 i 头奶牛的方案数:
dp[i−1][j−1][((t+n)−i)
可以被整除即:t==0
最终所求为dp[n][k][0]
#include <vector>
#include <iostream>
#include <string>
using namespace std;
//#define debug_
int func(int n, int k)
{
vector<vector<int>> dp;
vector<int> vec;
vec.resize(n + 1);
dp.resize(k + 1, vec);
dp[0][0] = 1;
for (auto i = 1; i < n + 1; ++i)//前i头奶牛
{
for (auto j = k; j > 0; --j)//选择j头奶牛
{
for (auto t = 0; t < n; ++t)//余t
{
dp[j][t] = (dp[j][t] + dp[j - 1][((t + n) - i) % n]) % 1000000007;
}
}
}
return dp[k][0];
}
int main()
{
int n, k;
#ifdef debug_
n = 7;
k = 4;
#else
cin >> n;
cin >> k;
#endif
cout << func(n, k);
return 0;
}