题意:长度为1的01序列,其中有m个1,每次操作可以将某个1旁边的0改成1,求方案数,对10^9+7取模
/* 又是一道数论,没想出正解来,打了个暴力 这个题可以等价于给出一个01序列,每次可以把某个1旁边的0变成1,直到序列全部为1。那么我们可以把这个序列以初始的1为分界点分成若干段num,每一段的取的方案数是2^(len-1)(除了第一段和最后一段之外,第一段和最后一段是1),那么现在的问题就变成了从num段中每次取一个的方案数,是n!,因为里面有重复的,所以变成 num!/(len1!*len2!* …… *) 。 答案就是 fangan1*fangan2*……*num!/(len1!*len2!* …… *)。 至于有除法的mod,不会逆元,用质因数分解做的,这里涉及到分解 n!的一个定理: 当第i个素数为P 时,c[i]= n/p+n/(p*p)+n/(p*p*p)……(直到n/(p*……*p变成0) */ #include<cstdio> #include<iostream> #define N 100010 #define ll long long #define mod 1000000007 using namespace std; ll len[N],prime[N],c[N],num,vis[N],f[N],n,m,ans=1; ll pow(ll x,ll y) { ll tot=1; for(ll i=1;i<=y;i++)tot*=x,tot%=mod; return tot; } void j1(ll x) { for(ll i=1;i<=num;i++) { ll P=prime[i]; while(P<=n) { c[i]+=x/P; P*=prime[i]; } } } void j2(ll x) { for(ll i=1;i<=num;i++) { ll P=prime[i]; while(P<=n) { c[i]-=x/P; P*=prime[i]; } } } void Prime() { for(int i=2;i<=n;i++) if(!f[i]) { prime[++num]=i; for(int j=2;i*j<=n;j++) f[i*j]=1; } } int main() { //freopen("jh.in","r",stdin); freopen("lantern.in","r",stdin); freopen("lantern.out","w",stdout); cin>>n>>m; for(ll i=1;i<=m;i++) { ll x;cin>>x; vis[x]=1; } ll sum=0;vis[n+1]=1; for(ll i=1;i<=n+1;i++) if(vis[i])len[++len[0]]=sum,sum=0; else sum++; Prime();j1(n-m); for(int i=1;i<=len[0];i++) j2(len[i]); for(int i=2;i<len[0];i++) ans=ans*pow(2,len[i]-1),ans%=mod; for(int i=1;i<=num;i++) ans*=pow(prime[i],c[i]),ans%=mod; cout<<ans; return 0; }