2014 编程之美复赛 题目1 : 组队 (错排)


题目1 : 组队

时间限制: 2000ms
单点时限: 1000ms
内存限制: 256MB

描述

有N支队伍,每个队伍有Ai个选手。

现在,这N支队伍想要进行交流:队伍之间交换选手,使得交换完后,每个队伍有且仅有1人和之前不同。

所以我们想知道,总共存在多少种可行的交换方案。两种交换方案不同,当且仅当,交换后的至少有一支队伍人员的集合不同。


输入

第一行一个整数T (1 ≤ T ≤ 10),表示数据组数。

接下来是T组输入数据,测试数据之间没有空行。

每组数据格式如下:

第一行一个整数N 。第二行N个整数,Ai (1 ≤ Ai≤ 100)


输出

对每组数据,先输出“Case x: ”,x表示是第几组数据。然后输出一个整数,表示有多少种可行的交换方案。由于答案可能很大,只需要输出除以109+7之后的余数即可。


数据范围

小数据:1 ≤ N ≤ 10

大数据:1 ≤  N ≤ 100


样例解释

3 * 3种交换方法都行。


样例输入
1
2
3 3
样例输出
Case 1: 9


每个组选一个人 用来交换, 使得每个人 最后的排列不在原来的组,求总方案数。
其实 和 每个组的人数没有关系,只是最后结果把每个组的人数乘起来就可以了。
这就是 错排了。 最大数据为100, 就是如何计算错排 的 方案数了。 
可以这样考虑: 假设有n个人,第一个人可放在(2~n)的任一个组里,共n-1种放法,设第一个人放在了第k个组里,若此时第k个人放在了第1个组里,则只要将剩下的n-2错排,即f(n-2),若第k个人没有放在了第1个组里,可将第1个人的组的位置看成是“第k个组”,即将n-1个人错排,即为f(n-1)

由递推可得,f(n)=(n-1)*(f(n-1)+f(n-2))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1000000000
#define MOD 1000000007
typedef long long  LL;
#define N 110
LL dp[N],n;
int main()
{
	int t,time=0;
	dp[1]=0; dp[2]=1;
	for(LL i=3;i<=101;i++)
	{
		dp[i]=(i-1)*(dp[i-1]+dp[i-2]); dp[i]%=MOD;
	}
	scanf("%d",&t);
	while(t--)
	{
		LL ans=1;
		LL tmp;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&tmp);
			ans*=tmp; ans%=MOD;
		}
		ans*=dp[n]; ans%=MOD;
		printf("Case %d: %lld\n",++time,ans);
	}
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值