点亮灯笼

 

 

 

题解:考虑题意,所修改的位置实际上是若干段,每段有一段或者两端可以修改。

处于最左边和最右边的两端由于只能从一边开始点灯,因此方案数为1,而其余每一段内的方案数为2^(l-1)。

 

 

 

 

 其中只考虑每个区间都是从一端一直点燃到另一端。则方案数为(n-m!)/(p1!*p2!*p3!*.....*pk1),其中pi!表示第i端全排列,(n-m)!表示总区间的全排列。这只是一种情况,然后再乘以每个区间的方案数即为最终答案。

ps:由于阶乘会导致最后的数非常大,因此可将其分解为质因子相乘的形式。除以的时候只需进行质因子的幂运算即可。最后将所有的质因子相乘。

 

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 100100
#define ll long long
const int M=1e9+7;
using namespace std;
int n,m,sum(0),num(0);
int dr[N],zs[N],ff[N];
ll ans=1;
bool f[N]={0};
struct node
{
    ll l,s;//l每一段区间的长度,s每一段区间的方案数 
}la[N];
void xx()//欧拉筛法求素数。背过模板就好了。 
{
    for (int i=2;i<=n;i++)
      {
           if (!f[i]) zs[++num]=i;
         for (int j=1;j<=num,zs[j]*i<=n;j++)
              {
                  f[zs[j]*i]=1;
                  if (!(i%zs[j])) break;    
              } 
      }
}
ll jc(ll p,ll k)//快速幂 
{
    ll ans=1;
    while (k)
      {
           if (k&1) ans=ans*p%M;
           p=p*p%M;
           k>>=1;
      }
    return ans;
}
int main()
{
    freopen("lantern.in","r",stdin);
    freopen("lantern.out","w",stdout);
    
    scanf("%d%d",&n,&m);
    xx();
    for (int i=1;i<=m;i++) scanf("%d",&dr[i]);  
    sort(dr+1,dr+m+1);
    if (dr[1]>1)
      {
         la[++sum].l=dr[1]-1;
         la[sum].s=1;
      }
    if (dr[m]<n)
      {
           la[++sum].l=n-dr[m];
           la[sum].s=1;
      }
    for (int i=2;i<=m;i++)
      {
            if (dr[i]-dr[i-1]-1) 
              {
                 la[++sum].l=dr[i]-dr[i-1]-1;
               la[sum].s=jc(2,la[sum].l-1);    
            }
      }
       for (int i=1;i<=num;i++)//(n-m)!表示成质因子相乘的形式 
         {
         ll t=n-m;
         while (t)
           {
                 ff[i]+=t/zs[i];
                 t/=zs[i];
           }
      }
    for (int i=1;i<=sum;i++)//求出每个区间的全排列pi 
      for (int j=1;j<=num;j++)
        {
            ll t=la[i].l;
            while (t)
              {
                   ff[j]-=t/zs[j];
                   t/=zs[j];
              }
        }
        
    for (int i=1;i<=num;i++)
       ans=ans*jc(zs[i],ff[i])%M;
    for (int i=1;i<=sum;i++)
      ans=ans*la[i].s%M;
     cout<<ans<<endl;
     
     fclose(stdin);
     fclose(stdout);
     return 0; 
}
100

 

posted @ 2016-10-24 21:32  外婆桥  阅读(204)  评论(0编辑  收藏  举报