题解 arc104e Random LIS
Description
Solution
观察到 \(n\) 只有 \(6\), 考虑枚举最后 \(x_i\) 之间的大小关系 .
枚举方式是先枚举最后有几个不相等的数 , 然后指定每个 \(x_i\) 的排名 .
最多只有 \(4683\) 种 .
枚举大小关系后可以直接求出最长上升子序列长度 .
然后要算的就是满足这样的排名的 \(x_i\) 的情况数 .
问题可以转化为:
给定 \(lim_{1-n}\)
求满足 \(1\leq x_i\leq lim_i\) 的上升序列 \(x\) 的个数 .
把 \(lim_i\leftarrow lim_i-i+1\)
求满足 \(1\leq x_i\leq lim_i\) 的不降序列 \(x\) 的个数 .
设 \(f_{i,j}\) 为考虑的前 \(i\) 个数 , 最后一个数权值为 \(j\) 的情况数 .
添加 \(lim_{n+1}=\infty\) , 答案为 \(f_{n+1,\infty}\)
\(f\) 的转移式为
\(f_{i,j}=\begin{cases}\sum\limits_{k\leq j}f_{i-1,k},&1\leq j\leq lim_i\\0,&(other)\end{cases}\)
把 \(f_{i}\) 看做一个函数 .
则每次的转移可以看做
- 修改 \(f_{i}\) 的有效长度 .
- 把 \(f_{i}\) 变为 \(f_{i}\) 的前缀和 .
观察到 \(f_{i}\) 为最多有 \(i\) 段的分段函数 , 每一段内都可写成不超过 \(i-1\) 次的多项式 .
那么分别对每一段做前缀和 , 然后加上之前的段的贡献即可 .
设之前的段的贡献为 \(bas\) , 该段左端点为 \(l\) .
那么就是给定 \(f(x)=\sum\limits_{i=0}^ma_ix^i\)
计算
\(\begin{aligned}g(x)&=bas+\sum\limits_{i=l}^xf(i)\\&=bas+\sum\limits_{i=l}^x\sum\limits_{j=0}^mi^ja_j\\&=\sum\limits_{i=0}^x\sum\limits_{j=0}^mi^ja_j+bas-\sum\limits_{i=1}^{l-1}\sum\limits_{j=0}^mi^ja_j\end{aligned}\)
记 \(S_i(x)=\sum\limits_{j=1}^xj^i\)
\(\begin{aligned}g(x)&=\sum\limits_{j=0}^ma_jS_j(x)+bas-\sum\limits_{j=0}^ma_jS_j(l-1)\end{aligned}\)
\(S_i(x)\) 可以由公式
\(\displaystyle S_k(x)=\frac{(x+1)^{\underline {k+1}}}{k+1}-\sum\limits_{i=0}^{k-1}\begin{bmatrix}k\\i\end{bmatrix}S_i(x)\)
递推得出 .
证明见 大佬博客
注意这里 \(\begin{bmatrix}k\\i\end{bmatrix}\) 为有符号第一类斯特林数 .
递推公式为 \(\begin{bmatrix}n\\m\end{bmatrix}=\begin{bmatrix}n-1\\m-1\end{bmatrix}-(n-1)\begin{bmatrix}n-1\\m\end{bmatrix}\)
那么这样就可以直接求出 \(f_{n+1}\)
那么最后一段的常数项就是答案 .
时间复杂度 \(O(懒得算)\)
Code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int read()
{
int ret=0;bool f=0;char c=getchar();
while(c>'9'||c<'0')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int mod=1e9+7;
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=(ll)a*a%mod)if(b&1)ret=(ll)ret*a%mod;return ret;}
int s[10][10];
struct poly
{
vector<int>v;
int&operator[](const int &i){return v[i];}
void set(int l){v.resize(l);}
int len(){return v.size();}
poly operator *(poly x)
{
poly ret;
ret.set(len()+x.len()-1);
for(int i=0;i<len();i++)
for(int j=0;j<x.len();j++)
{
(ret[i+j]+=(ll)v[i]*x[j]%mod)%=mod;
}
return ret;
}
poly operator -(poly x)
{
poly ret;
ret.set(max(len(),x.len()));
for(int i=0;i<len();i++)ret[i]=v[i];
for(int i=0;i<x.len();i++)ret[i]=(ret[i]-x[i]+mod)%mod;
return ret;
}
poly operator +(poly x)
{
poly ret;
ret.set(max(len(),x.len()));
for(int i=0;i<len();i++)ret[i]=v[i];
for(int i=0;i<x.len();i++)ret[i]=(ret[i]+x[i])%mod;
return ret;
}
int val(int x)
{
int ret=0,now=1;
for(int &i:v)
{
(ret+=(ll)now*i%mod)%=mod;
now=(ll)now*x%mod;
}
return ret;
}
}S[7];
void prework()
{
int k=6;
s[0][0]=1;
for(int i=1;i<=k;i++)
for(int j=1;j<=i;j++)
s[i][j]=(s[i-1][j-1]-(ll)s[i-1][j]*(i-1)%mod+mod)%mod;
S[0]={{0,1}};
for(int i=1;i<=k;i++)
{
S[i]={{1}};
for(int j=0;j<=i;j++)
S[i]=S[i]*(poly){{(1-j+mod)%mod,1}};
int inv=qpow(i+1,mod-2);
for(int &j:S[i].v)j=(ll)j*inv%mod;
for(int j=0;j<=i-1;j++)S[i]=S[i]-(poly){{s[i][j]}}*S[j];
}
}
poly getpre(poly f)
{
poly ret;
for(int i=0;i<f.len();i++)ret=ret+(poly){{f[i]}}*S[i];
return ret;
}
int n,a[10];
int ans;
struct Data
{
struct node{int l,r;poly f;};
vector<node>v;
void set(int len)
{
while(v.back().l>len)v.pop_back();
if(v.back().r<len)v.push_back({v.back().r+1,len,{{0}}});
if(v.back().r>len)v.back().r=len;
}
void presum()
{
int bas=0;
for(auto &i:v)
{
for(int j=0;j<i.f.len();j++)bas=(bas-(ll)i.f[j]*S[j].val(i.l-1)%mod+mod)%mod;
i.f=getpre(i.f);
(i.f.v[0]+=bas)%=mod;
bas=i.f.val(i.r);
}
}
};
int calc(vector<int>&lim)
{
Data ret;
for(int i=0;i<lim.size();i++)if(lim[i]<=0)return 0;
lim.push_back(1e9);
ret.v.push_back({1,lim[0],{{1}}});
for(int i=1;i<lim.size();i++)
{
ret.set(lim[i]);
ret.presum();
}
return ret.v.back().f.val(1e9);
}
vector<int>id[10];int to;
void solve()
{
static int val[10],f[10];
for(int i=1;i<=to;i++)if(id[i].empty())return;
vector<int>tmp;
for(int i=1;i<=to;i++)
{
int mi=1e9;
for(int &j:id[i])mi=min(mi,a[j]);
mi=mi-i+1;
tmp.push_back(mi);
}
for(int i=1;i<=to;i++)
for(int &j:id[i])val[j]=i;
int mx=0;
for(int i=1;i<=n;i++)
{
f[i]=0;
for(int j=1;j<i;j++)if(val[j]<val[i])f[i]=max(f[i],f[j]);
f[i]++;mx=max(mx,f[i]);
}
int ret=(ll)calc(tmp)*mx%mod;
(ans+=ret)%=mod;
}
void dfs(int now)
{
if(now==n+1){solve();return;}
for(int i=1;i<=to;i++)
{
id[i].push_back(now);
dfs(now+1);
id[i].pop_back();
}
}
int main()
{
generate_n(a+1,n=read(),read);prework();
for(int i=1;i<=n;i++)to=i,dfs(1);
for(int i=1;i<=n;i++)ans=(ll)ans*qpow(a[i],mod-2)%mod;
printf("%d\n",ans);
return 0;
}