题目地址:http://codeforces.com/contest/294/problem/C
解析参考地址:http://hi.baidu.com/zyz913614263/item/796b1a7c8bda6405d0dcb30c
关键就是求(n-k)!/(x!*y!……*z! )*2^(m-1),我是直接把阶乘分解成质因子的,然后相减,再求次方,然后相乘求解。(具体见代码。)
注:这种方法是自己想出来的奥,不过仅仅适合数据比较小的时候,不然会超时,比如在做CF#181 div2C的时候就不可以用这种方法了。
源代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cmath>
#include <stdio.h>
using namespace std;
int b[10005];
#define MOD 1000000007
int a[1005];//存储上面的分解
int c[1005];//存储下面的分解
int prime[1100];
int flag[1100];
int ans[1005];
void init()
{
memset(flag,0,sizeof(flag));
int q=0;
for(int i=2;i<1100;i++) //注意要求到比1000大的一个质数,作为后来结束的标志(在这runtime error了次)
{
if(!flag[i])
{
prime[q++]=i;
for(int j=i+i;j<1100;j+=i)
flag[j]=1;
}
}
}
void fun1(int k) //求上面(n-k)!的分解情况
{
for(int i=0;k>=prime[i];i++)
{
int j=prime[i];
int num=0;
while(k>=j)
{
num+=k/j;
j*=prime[i];
}
a[prime[i]]+=num;
}
}
void fun2(int k) //求下面的分解情况
{
for(int i=0;k>=prime[i];i++)
{
int j=prime[i];
int num=0;
while(k>=j)
{
num+=k/j;
j*=prime[i];
}
c[prime[i]]+=num;
}
}
long long Pow(int x,int y) //求x^y%MOD
{
if(y==0) return 1;
long long mid=(long long)x;
while(y>1)
{
mid=(mid*x)%MOD;
y--;
}
return mid%MOD;
}
int main()
{
int m,n;
int t,i,j,k,l;
int num;
init();
while(cin>>n>>k)
{
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
for(i=0;i<k;i++) cin>>b[i];
sort(b,b+k);
fun1(n-k);
if(b[0]>2) fun2(b[0]-1); //求两端的特殊情况。
if(b[k-1]<n-1) fun2(n-b[k-1]);
for(i=1;i<k;i++) //中间的情况,这是要加上2^(mid-1)
{
int mid=b[i]-b[i-1]-1;
if(mid<=1) continue;
else
{
fun2(mid);
a[2]+=(mid-1);
}
}
for(i=0;prime[i]<=n-k;i++)
{
ans[prime[i]]=a[prime[i]]-c[prime[i]];
}
long long re=1;
for(i=0;prime[i]<=n-k;i++)
{
re=(re*Pow(prime[i],ans[prime[i]]))%MOD;
}
cout<<re<<endl;
}
return 0;
}