模型转化;要是转化不出来就啥都不会了。
这个(prod_{i=1}^ka_i^2)看起来并不好直接处理,我们考虑(a_i^2)的组合意义,就是把两个可区分的球放到(a_i)个可区分的盒子,允许一个盒子放多个的方案数;于是我们可以搞一个dp状物,设(f_{i,j})表示处理了前(i)个位置,当前这一段共放了(j)个球,转移的话就枚举一下这个位置放哪几个球,以及是否要另起一段,由于第二维只有(0/1/2),所以复杂度是(O(n))的。
再来考虑一下关键点的限制,发现这个关键点的限制本质上就是使得这次转移不能另起一段,于是也很好处理。
不难发现这两种转移都可以矩乘优化,由于两种转移的矩阵不一样,关键点个数只有(10^5)级别,所以我们用矩阵快速幂处理没有关键点的转移,就能做到(O(w^3mlog n))的复杂度,(w)是矩阵大小;但是不难发现我们并不需要最后的矩阵,我们要的只是一个向量乘矩阵的结果,于是我们可以预处理所有矩阵的(2)次幂,拿一个向量直接乘过去就好了,由于向量乘矩阵的是(O(w^2))的,所以复杂度是(O(w^3log n+w^2mlog n))。看起来好像没快多少,但少一个(w)就跑到了最优解。
代码
#include<bits/stdc++.h>
#define re register
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=1e9+7;const int maxn=1e5+5;
int n,m,b[maxn];
struct Vector{int v[3];}D,ans;
struct Matrix{int a[3][3];}C,pw[32],G;
inline int qm(int x) {return x>=mod?x-mod:x;}
inline Matrix operator*(const Matrix &A,const Matrix &B) {
for(re int i=0;i<3;i++)
for(re int j=0;j<3;j++)C.a[i][j]=0;
for(re int k=0;k<3;k++)
for(re int i=0;i<3;i++)
for(re int j=0;j<3;j++)C.a[i][j]=qm(C.a[i][j]+1ll*A.a[i][k]*B.a[k][j]%mod);
return C;
}
inline Vector operator^(const Vector &A,const Matrix &B) {
for(re int i=0;i<3;i++)D.v[i]=0;
for(re int i=0;i<3;i++)
for(re int j=0;j<3;j++)D.v[i]=qm(D.v[i]+1ll*A.v[j]*B.a[i][j]%mod);
return D;
}
inline void mul(int x) {
for(re int i=0;(1<<i)<=x;i++)
if(x>>i&1) ans=ans^pw[i];
}
int main() {
n=read(),m=read();ans.v[0]=1;
for(re int i=1;i<=m;i++)b[i]=read();
std::sort(b+1,b+m+1);
for(re int i=0;i<3;i++)
for(re int j=0;j<3;j++) pw[0].a[i][j]=1;
pw[0].a[0][0]=pw[0].a[1][0]=2,pw[0].a[1][2]=0;
for(re int i=1;(1<<i)<=n;++i) pw[i]=pw[i-1]*pw[i-1];
G.a[1][0]=2;G.a[0][0]=G.a[1][1]=G.a[2][2]=G.a[2][0]=G.a[2][1]=1;
for(re int i=1;i<=m;i++) mul(b[i]-b[i-1]-1),ans=ans^G;
mul(n-b[m]);printf("%d
",ans.v[2]);
return 0;
}