题解 P6009 【[USACO20JAN]Non-Decreasing Subsequences P】
题意
给一个长度为
题解
考虑如何求
注意到值域范围很小,于是可以
注意到可以维护矩阵来进行转移,第
这样可以求得答案为
现在把他迁移到任意区间上来,得到
考虑差分,得到
考虑这个东西的逆矩阵是啥。根据人类智慧得到
于是维护
和
就可以得到答案为
但是,暴力矩乘不可取,考虑优化。
注意到
右乘和左乘都可以
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51,MOD=1e9+7;
ll n,kk,qcnt,l,r,res;
ll x[MAXN],p[25][25],f[MAXN][25],g[MAXN][25];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
int main()
{
n=read(),kk=read();
for(register int i=1;i<=kk;i++)
{
p[i][i]=1;
}
for(register int i=1;i<=n;i++)
{
x[i]=read();
for(register int j=1;j<=kk;j++)
{
for(register int k=x[i];k;k--)
{
p[j][x[i]]=(p[j][k]+p[j][x[i]])%MOD;
}
}
for(register int j=1;j<=kk;j++)
{
for(register int k=1;k<=kk;k++)
{
f[i][j]=(f[i][j]+p[j][k])%MOD;
}
}
}
memset(p,0,sizeof(p)),qcnt=read(),g[0][1]=1;
for(register int i=1;i<=kk;i++)
{
p[i][i]=1;
}
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=x[i];j++)
{
for(register int k=1;k<=kk;k++)
{
p[j][k]=(p[j][k]+(li)(5e8+3)*p[x[i]][k]%MOD)%MOD;
}
}
for(register int j=1;j<=kk;j++)
{
g[i][j]=p[1][j];
}
}
for(register int i=0;i<qcnt;i++)
{
l=read(),r=read(),res=0;
for(register int j=1;j<=kk;j++)
{
res=(res+(li)g[l-1][j]*f[r][j]%MOD)%MOD;
}
printf("%d\n",res);
}
}