7-1 礼尚往来 (10分)
吉哥还是那个吉哥,那个江湖人称“叽叽哥”的基哥。每当节日来临,女友众多的叽叽哥总是能从全国各地的女友那里收到各种礼物。有礼物收到当然值得高兴,但回礼确是件麻烦的事!无论多麻烦,总不好意思收礼而不回礼,那也不是叽叽哥的风格。现在,即爱面子又抠门的叽叽哥想出了一个绝妙的好办法:他准备将各个女友送来的礼物合理分配,再回送不同女友,这样就不用再花钱买礼物了!假设叽叽哥的n个女友每人送他一个礼物(每个人送的礼物都不相同),现在他需要合理安排,再回送每个女友一份礼物,重点是,回送的礼物不能是这个女友之前送他的那个礼物,不然,叽叽哥可就摊上事了,摊上大事了…现在,叽叽哥想知道总共有多少种满足条件的回送礼物方案呢?
输入格式:
输入数据第一行是个正整数T,表示总共有T组测试数据(T <= 100); 每组数据包含一个正整数n,表示叽叽哥的女友个数为n( 1 <= n <= 100 )。
输出格式:
请输出可能的方案数,因为方案数可能比较大,请将结果对1000000007 取模后再输出。(提示:在递推过程中,不断求余防止数据太大导致数据溢出。) 每组输出占一行。
输入样例:
3
1
2
4
输出样例:
0
1
9
解题
- 这题不要盲目去解,一开始我就是这样,结果太复杂了,还写不出通项式,后来重新分析发现是个递推题。
- 设dp[n] 就表示n个人的方案
- 如下图,共有n个人,第一个位置(A)给除A以外的(n - 1) 人中的其中一人,则可有(n - 1)个选择,余下n - 1人中,有n - 2 人是有重复的,现在先假设这n - 1人全部是有重复的,即假设F = A,那么这n - 1人一共就有dp[n - 1]种方案,显然如果直接这么计算,少算了A 在 F 位置的次数,现在把A直接放在F位置,余下n - 2 个位置,全部是有重复的n - 2 个,即dp[n - 2],综上有:
- dp[n] = (n - 1) * (dp[n - 1] + dp[n - 2]); 结果在对p取余即可。
代码
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
typedef long long ll;
const int p = 1000000007;
const int maxn = 102;
ll dp[maxn];
int main() {
int T, n;
dp[1] = 0;
dp[2] = 1;
for (int i = 3; i < maxn; i++) {
dp[i] = (i - 1LL) * (dp[i - 1] + dp[i - 2]) % p;
}
cin >> T;
// for (int i = 1; i <= T; i++) {
// cout << i << " " << dp[i] << endl;
// }
while (T--) {
cin >> n;
cout << dp[n] << endl;
}
system("pause");
return 0;
}