非確定性有窮狀態決策自動機練習題Vol.3 D. Dp搬運工3

liuchanglc發表於2020-08-19

非確定性有窮狀態決策自動機練習題Vol.3 D. Dp搬運工3

題目描述

給定兩個長度為 \(n\) 的排列,定義 \(magic(A,B)=∑_{i=1}^nmax(Ai,Bi)\)
現在給定 \(n\),\(K\) 問有多少對 \((A,B)\) 滿足 \(magic(A,B)≥K\)

分析

首先轉化一下,我們固定排列 \(B\) 為 $1∼n $,最後答案乘個 \(n!\) 就好了

我們設 \(f[i][j][k]\) 為 考慮到第 \(i\) 個位置,\(i\) 之前有 \(j\) 個位置沒有填,當前產生的價值為 \(k\) 的方案數

我們可以選擇在 \(i\) 的位置不填數,此時直接轉移即可

\(f[i][j+1][k]=f[i][j+1][k]+f[i-1][j][k]\)

我們可以把當前的 \(i\) 插入到之前沒有填過的 \(j\) 個位置或者從之前沒有用過的 \(j\) 個數中選擇一個填到 \(i\) 所在的位置,還可以把數字 \(i\) 填入 \(i\) 的位置

此時的轉移方程為
\(f[i][j][k+i]=f[i][j][k+i]+f[i-1][j][k] \times (j \times 2+1)\)

我們還可以既把當前的 \(i\) 插入到之前沒有填過的 \(j\) 個位置又從之前沒有用過的 \(j\) 個數中選擇一個填到 \(i\) 所在的位置,此時

\(f[i][j-1][k+i+i]=f[i][j-1][k+i+i]+f[i-1][j][k] \times j \times j\)

程式碼

#include<cstdio>
#include<algorithm>
const int maxn=55;
const int mod=998244353;
long long f[maxn][maxn][maxn*maxn];
int n,k;
int main(){
	freopen("D.in","r",stdin);
	freopen("D.out","w",stdout);
	scanf("%d%d",&n,&k);
	f[1][0][1]=f[1][1][0]=1;
	for(int i=2;i<=n;i++){
		int maxj=std::min(i-1,n-i+1);
		int maxk=i*i;
		for(int j=0;j<=maxj;j++){
			for(int k=0;k<=maxk;k++){
				if(f[i-1][j][k]){
					f[i][j+1][k]=(f[i][j+1][k]+f[i-1][j][k])%mod;
					f[i][j][k+i]=(f[i][j][k+i]+f[i-1][j][k]*(j*2LL+1))%mod;
					if(j) f[i][j-1][k+i+i]=(f[i][j-1][k+i+i]+f[i-1][j][k]*j*j*1LL)%mod;
				}
			}
		}
	}
	long long ans=0;
	for(int i=k;i<=n*n;i++){
		ans=(ans+f[n][0][i])%mod;
	}
	for(int i=2;i<=n;i++){
		ans=ans*1LL*i%mod;
	}
	printf("%lld\n",ans);
	return 0;
}

相關文章