BZOJ4574: [Zjoi2016]线段树【DP】

4574: [Zjoi2016]线段树

这个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[L1],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][i1][j][k](nj),表示上一次的区间为 [ 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] [nj+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][i1][j][k](i1),同上。

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(i1)i2(nj)(nj+1)2(ji+1)(ji+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

你可能感兴趣的:(BZOJ,DP)