Problem F: 通话调研
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 254 Solved: 36
[ Submit][ Status][ Web Board]
Description
埃森哲的小Q最近在做市场调研,每天要打很多的电话。一天打的累了,正在喝咖啡休息。不过爱动脑筋的小Q的脑袋可没有闲着,他在思考这样一件事:如果一共有N个人(编号1-N),假设所有人都相互认识。每个人都拥有一部电话,且每时每刻他们都有可能在跟另一个人通话(当然也可以没有打电话而在干别的事情)。
我们假设每次通话只限于两人通话,则在某个时刻,我们突然检查所有人的状态,我们想知道所有人的通话状态数有多少种。举个栗子(为什么是栗子!):当前有2个人,则在某个时刻,我们突然检查这2个人的状态,则总共有2种情况,要么1号和2号在通话,要么各自在做着别的事情。
当然聪明的小Q想的问题不会这么简单,小Q还会给出更多的约束,即已知在检查的那个时刻,有M个人一定不在通话中。现在请你计算一下总的情况数。
Input
多组测试数据。
对于每组数据:
第1行:输入两个整数N和M(1 <= N <= 1,000,000, 0 <= M <= N)。
第2行:输入M个整数Ai(1 <= Ai <= N)分别代表那些肯定不在通话的人编号,我们保证输入序列没有重复数。
Output
对于每组数据,输出一行,包含一个整数,代表总的情况数。由于最后答案过大,请把答案对1,000,000,007(1e9 + 7)取模后输出。
Sample Input
2 122 0
Sample Output
12
HINT
定义函数F(x,y)为共n个人,有m个人一定没有打电话时,总的情况数。
发现,这m个人不会对剩下的人造成影响,而且他们只存在一种情况,都不打电话。
所以转化为,F(x,y) = F(x-y,0)。定义f(x) = F(x,0)
如何计算f(x)?
假设有序。若第x个人不打电话,则同上讨论结果,转化为相同子问题f(x-1)。若第x个人打电话,则他只能和剩余x-1个人中一个人打电话,有x-1种选择。并且这两个人都不能再和别人打电话,因此转化为相同子问题f(x-2)。则f(x) = f(x-1)+(x-1)*f(x-2)。
#include <cstdio>
#include <string>
#include <cstring>
inline int getint()
{
int res=0;char tmp;bool sgn=1;
do tmp=getchar();
while (!isdigit(tmp)&&tmp!='-');
if (tmp=='-'){sgn=0;tmp=getchar();}
do res=(res<<3)+(res<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?res:-res;
}
typedef long long ll;
const ll MOD = 1000000007;
ll f[1000010];
int main()
{
f[1] = 1;
f[2] = 2;
for (int i=3;i<=1000000;i++)
{
f[i] = (f[i-1] + (f[i-2] * (i-1))%MOD)%MOD;
}
int n,m;
bool first = true;
while (scanf("%d%d",&n,&m)==2)
{
if (!first)
printf("\n");
first = false;
int tmp;
for (int i=1;i<=m;i++) scanf("%d",&tmp);
printf("%d",int(f[n-m]));
}
return 0;
}