这个DP有点玄学, F [ w ] [ i ] [ L ] [ R ] F[w][i][L][R] F[w][i][L][R]表示第 i i i轮 m i n ( a [ i ] , i ∈ [ L , R ] ) ≤ w < m i n ( a [ L − 1 ] , a [ R + 1 ] ) min(a[i],i\in[L,R])\le w <min(a[L-1],a[R+1]) min(a[i],i∈[L,R])≤w<min(a[L−1],a[R+1])。
考虑转移
1. F [ w ] [ i ] [ j ] [ t ( t < k ) ] + = F [ w ] [ i − 1 ] [ j ] [ k ] ∗ ( n − j ) F[w][i][j][t(t<k)]+=F[w][i-1][j][k]*(n-j) F[w][i][j][t(t<k)]+=F[w][i−1][j][k]∗(n−j),表示上一次的区间为 [ j , k ] [j,k] [j,k]这一次选择了 [ t + 1 , p ( p > R ) ] [t+1,p(p>R)] [t+1,p(p>R)], p p p可以在 [ n − j + 1 , n ] [n-j+1,n] [n−j+1,n]之间随便选,这样选择包括了 R + 1 R+1 R+1所以不满足定义了,所以区间需要缩小。
2. F [ w ] [ i ] [ t ( t > j ) ] [ k ] + = F [ w ] [ i − 1 ] [ j ] [ k ] ∗ ( i − 1 ) F[w][i][t(t>j)][k]+=F[w][i-1][j][k]*(i-1) F[w][i][t(t>j)][k]+=F[w][i−1][j][k]∗(i−1),同上。
3. F [ w ] [ i ] [ j ] [ k ] + = F [ w ] [ i ] [ j ] [ k ] ∗ ( i − 1 ) ∗ i 2 ∗ ( n − j ) ∗ ( n − j + 1 ) 2 ∗ ( j − i + 1 ) ∗ ( j − i + 2 ) 2 F[w][i][j][k]+=F[w][i][j][k]*\frac{(i-1)*i}{2}*\frac{(n-j)*(n-j+1)}{2}*\frac{(j-i+1)*(j-i+2)}{2} F[w][i][j][k]+=F[w][i][j][k]∗2(i−1)∗i∗2(n−j)∗(n−j+1)∗2(j−i+1)∗(j−i+2)
也就是我们现在要取一个区间,使得要么被包含要么没有交集。
我们一开始枚举w,这样DP就可以少一维了,然后i这维滚一下。
然后前缀和优化DP就可以了。时间复杂度O(n^4),虽然跑不满,但是还是要卡一下常才行。
#include
#include
#include
using namespace std;
const int MOD=1e9+7;
typedef long long LL;
int n,q,m,Rank[405],b[405],a[405],cnt[405];
LL f[2][405][405],Ans[405],A[405][405],Sum[405][405];
void MO(LL &x){x-=(x>=MOD?MOD:0);}
void Solve(int L,int R,int K){
memset(f,0,sizeof(f));f[0][L][R]=1;
int now=1;
for(int t=1;t<=q;t++,now^=1){
for(int i=L;i<=R;i++){
LL rt=0;
for(int j=R;j>=i;j--) f[now][i][j]=rt,rt+=f[now^1][i][j]*(n-j);
}
for(int j=L;j<=R;j++){
LL rt=0;
for(int i=L;i<=j;i++) f[now][i][j]+=rt,rt+=f[now^1][i][j]*(i-1);
}
for(int i=L;i<=R;i++)
for(int j=i;j<=R;j++) f[now][i][j]=(f[now][i][j]+f[now^1][i][j]*A[i][j])%MOD;
}
for(int i=L;i<=R;i++){
LL rt=0;
for(int j=R;j>=i;j--) MO(rt+=f[now^1][i][j]),MO(Sum[j][Rank[K]]+=rt);
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),Rank[i]=b[i]=a[i];
sort(b+1,b+1+n);m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) Rank[i]=lower_bound(b+1,b+1+m,Rank[i])-b;
for(int i=1;i<=n;i++) cnt[i]=i*(i+1)/2;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++) A[i][j]=cnt[i-1]+cnt[n-j]+cnt[j-i+1];
for(int i=1;i<=n;i++){
int L=i,R=i;
while(L>1&&a[L-1]<=a[i]) L--;
while(R