BZOJ4574: [Zjoi2016] 세그먼트 트리[DP]

3082 단어 BZOJDP

4574: [Zjoi2016] 세그먼트 트리


이 DP는 약간 현학적이고, F[w] [i] [L] [R] [w] [w] [i] [L] [L] [L] [R] [R] [i] [i] [L] [R] [L] [i] [L] [i] [L] [L] [L] [L] [L] [R] [R] [i] [L] [i] [[L] [i] [[L] [i] [L] [[L] [i] [L] [[L] [i] [L] [L] [[L] [R] [[L] [L] [R] [1] [4] [4] [4] [4] [4] [4] [Rmin(L] [4] [4]]]]], [4] [4] a[L -3 1], a[R+1]).
전환 고려
1. F [w] [i] [i] [j] [t(t R)] [t+1,p(p>R)] [t+1,p(p>R)]를 선택했고, ppp는 [n-j+1,n] [n-j+1,n] [n-3 j+1,n] [n]에서 마음대로 선택할 수 있고,이러한 선택은 R+1 R+1 R+1을 포함하기 때문에 정의를 만족시키지 못하기 때문에 구간을 축소해야 한다.
2. F [w] [i] [t(t> j)] [k] + = F [w] [i-3] [j] [k] [w] [w] F[w] [i] [t(t>j)] [k] [w] [k] [w] [i-1] [k] [k] [w] [w] [i] [t(t>j)] [k]
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가 1차원을 줄일 수 있다. 그리고 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

좋은 웹페이지 즐겨찾기