1 /******************************************************************************************************************************************************************************* 2 题目大意:给出一列灯,初始有一些点亮的灯,每次只能点亮与已经点亮的灯相邻的灯,问点亮所有灯的方案有多少种 3 题解: 4 首先利用初始已经点亮的灯分段,最左侧和最右侧的两段因为只有一侧有灯,所以单论这一段的话,点亮的方案只有一种。 5 对于中间的段落,因为两侧都有灯,所以每次都有两个灯备选,也就是有2n中方案。 6 然后因为各个段的点亮也有交叉的顺序,所以就是对于每一段采取类似于插板的组合方法,也就是C(numsum,sum)是当期分段的元素总数,num是当前段元素的总数 7 8 对于样例3: 1 2 3 4 5 6 7 8 9 10 11 9 有9个灯要打开...首先处理4前面的...放到9个要打开的任意位置C(9,3)..并且前面几个只有一种操作顺序(从4开始往左)...an=C(9,3)=84 10 再看5~7..此时还剩下9-3=6个空位置..把这三个放进去..C(6,3)..有5,6,7有四种开的顺序: ->5->6->7; 5<-6<-7<- , ->5->6 7<-,->5 6<-7<-四种..ans*=C(6,3)*4=6720 11 最后的9~11为C(3,3)只有一种开顺序..所以ans*=C(3,3)=6720... 12 可知对于被连个亮着的灯夹着的连续灯...若有k个.则有2^(k-1)种开顺序...顶左右两侧的..只能顺序过去... 13 14 ********************************************************************************************************************************************************************************/ 15 #include<bits/stdc++.h> 16 #define LL long long 17 using namespace std; 18 const int oo = 1e9+7; 19 const int maxn = 1005; 20 LL c[maxn][maxn],_2jie[maxn],a[maxn]; 21 inline void prework(){ 22 for (int i=0; i<=1000; ++i) c[i][0] = 1; 23 for (int i=1; i<=1000; ++i) 24 for (int j=1; j<=1000; ++j) c[i][j] = (c[i-1][j]+c[i-1][j-1])%oo; 25 _2jie[0] = 1; 26 for (int i=1; i<=1000; ++i) _2jie[i] = (_2jie[i-1]*2)% oo; 27 return; 28 } 29 int main(){ 30 int n,m; LL ans,num; prework(); 31 while (~scanf("%d%d",&n,&m)){ 32 for (int i=1; i<=m; ++i) scanf("%I64d",&a[i]); 33 sort(a+1,a+1+m); num = n-m; ans = c[num][a[1]-1]; num -= a[1]-1; 34 for (int i=2; i<=m; ++i){ 35 LL x= a[i] - a[i-1] -1; 36 if (x) ans =((ans*c[num][x])%oo*_2jie[x-1])%oo; else ans=(ans*c[num][x])%oo; 37 num -= a[i]-a[i-1]-1; 38 } 39 ans = (ans*c[num][n-a[m]])%oo; printf("%I64d ",ans); 40 } 41 return 0; 42 } 43 /********************************************************************************************************************************************************************************/