设$f[i][j]$表示考虑前$i$个人,第$i$个人在前$i$个人中排名为$j$的方案数。

对于大小关系相同的一段,转移可以看成求$k$次前/后缀和,任意一项对另一项的贡献仅和其下标差值有关,FFT加速即可。

时间复杂度$O(mn\log n)$。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=65555,M=32768,P=1000000007;
int n,m,i,j,k,t,o,len,L,R,a[30],b[N],f[N*3],ans,g[N],v[N],fin[N],fac[N],inv[N],pos[N];
inline void up(int&a,int b){(a+=b)>=P&&(a-=P);}
inline int C(int n,int m){return 1LL*fac[n]*inv[m]%P*inv[n-m]%P;}
namespace FFT{
struct comp{
long double r,i;comp(long double _r=0,long double _i=0){r=_r;i=_i;}
comp operator+(const comp&x){return comp(r+x.r,i+x.i);}
comp operator-(const comp&x){return comp(r-x.r,i-x.i);}
comp operator*(const comp&x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
comp conj(){return comp(r,-i);}
}A[N],B[N];
int a0[N],b0[N],a1[N],b1[N];
const long double pi=acos(-1.0);
void FFT(comp a[],int n,int t){
for(int i=1;i<n;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
for(int d=0;(1<<d)<n;d++){
int m=1<<d,m2=m<<1;
long double o=pi*2/m2*t;comp _w(cos(o),sin(o));
for(int i=0;i<n;i+=m2){
comp w(1,0);
for(int j=0;j<m;j++){
comp&A=a[i+j+m],&B=a[i+j],t=w*A;
A=B-t;B=B+t;w=w*_w;
}
}
}
if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;
}
void mul(int*a,int*b,int*c,int k){
int i,j;
for(i=0;i<k;i++)A[i]=comp(a[i],b[i]);
FFT(A,k,1);
for(i=0;i<k;i++){
j=(k-i)&(k-1);
B[i]=(A[i]*A[i]-(A[j]*A[j]).conj())*comp(0,-0.25);
}
FFT(B,k,-1);
for(i=0;i<k;i++)c[i]=((long long)(B[i].r+0.5))%P;
}
void mulmod(int*a,int*b,int*c,int k){
int i;
for(i=0;i<k;i++)a0[i]=a[i]/M,b0[i]=b[i]/M;
for(mul(a0,b0,a0,k),i=0;i<k;i++){
c[i]=1LL*a0[i]*M*M%P;
a1[i]=a[i]%M,b1[i]=b[i]%M;
}
for(mul(a1,b1,a1,k),i=0;i<k;i++){
c[i]=(a1[i]+c[i])%P,a0[i]=(a0[i]+a1[i])%P;
a1[i]=a[i]/M+a[i]%M,b1[i]=b[i]/M+b[i]%M;
}
for(mul(a1,b1,a1,k),i=0;i<k;i++)c[i]=(1LL*M*(a1[i]-a0[i]+P)+c[i])%P;
}
}
inline void solve(int len,int K){
int i,j,k;
for(k=1;k<=len;k<<=1);k<<=1;
j=__builtin_ctz(k)-1;
for(i=0;i<k;i++)pos[i]=pos[i>>1]>>1|((i&1)<<j);
for(i=0;i<=len;i++)v[i]=C(i+K-1,K-1);
for(g[0]=0;i<k;i++)v[i]=g[i]=0;
FFT::mulmod(g,v,fin,k);
for(i=1;i<=len;i++)g[i]=fin[i];
}
int main(){
scanf("%d%d",&n,&m);
for(fac[0]=i=1;i<=n*2;i++)fac[i]=1LL*fac[i-1]*i%P;
for(inv[0]=inv[1]=1,i=2;i<=n*2;i++)inv[i]=1LL*(P-P/i)*inv[P%i]%P;
for(i=2;i<=n*2;i++)inv[i]=1LL*inv[i-1]*inv[i]%P;
for(i=1;i<=m;i++)scanf("%d",&a[i]);
for(i=1;i<m;i++)for(j=a[i];j<a[i+1];j++)b[j]=i&1;
for(i=a[2],L=1+N,f[R=i+N]=1;i<n;i=j){
for(j=i;j<n&&b[i]==b[j];j++);
t=j-i;
for(k=L;k<=R;k++)g[k-L+1]=f[k];
len=R-L+1;
if(!b[i])reverse(g+1,g+len+1);
solve(len,t);
if(!b[i])reverse(g+1,g+len+1);
for(k=L;k<=R;k++)f[k]=g[k-L+1];
b[i]?L-=t:R+=t;
}
for(i=L;i<=R;i++)up(ans,f[i]);
return printf("%d",ans),0;
}

  

最新文章

  1. jQuery中 pageX,clientX,offsetX,layerX的区别
  2. Js解析浏览器路径的方法
  3. 图形学理论知识 BRDF 双向反射分布函数(Bidirectional Reflectance Distribution Function)
  4. LeetCode | Single Number II【转】
  5. (转)MVC中的Repository模式
  6. hdu4418(概率dp + 高斯消元)
  7. Android Manifest.xml详解
  8. 如何在Android SDK 下查看应用程序输出日志的方法
  9. 学习笔记——观察者模式Observer
  10. hb_gui配置heartbeat做MariaDB的高可用
  11. Webpack 2 视频教程 014 - 深入理解 Webpack 2 中的 loader
  12. JVM--02
  13. maven到Gradle,一些对比和分享
  14. Hadoop学习------Hadoop安装方式之(一):单机部署
  15. C中的malloc/free与C++中的new/delete的用法与区别
  16. Ex 2_23 如果一个数组超过半数的元素都相同时,该数组被称为含有一个主元素..._第二次作业
  17. Android动画知识汇总
  18. 网络量化——Quantized Convolutional Neural Networks for Mobile Devices
  19. Android-Thread线程的状态
  20. Python交互数据库(Mysql | Mongodb | Redis)

热门文章

  1. 步步為營-95-MyMVC 1.0
  2. sqoop无法导出parquet文件到mysql
  3. 五.hadoop 从mysql中读取数据写到hdfs
  4. 虚拟机下安装Centos7并配置Apache+PHP+Mysql+phpmyadmin+wordpress
  5. Ubuntu下Gradle环境配置
  6. vue 踩坑记录
  7. Java第三阶段学习(七、线程池、多线程)
  8. Codeforces Round #506 (Div. 3)
  9. 学习之&quot;setjmp和longjmp函数&quot;
  10. Tychonov Theorem