1. 程式人生 > 實用技巧 >2020.7.4模擬 資料結構 (ds)

2020.7.4模擬 資料結構 (ds)

題目描述

\(wobmaj\)\(N\)個數據結構,第\(i\)個數據結構具有工業指數\(A_i\)和包容指數\(B_i(B_i\le A_i)\)
他會不斷執行下面這個操作,直到無法再執行為止:
選擇二元組\((i,j)\),將第\(i\)個數據結構套進第\(j\)個數據結構裡,其中\(A_i<B_j\)
每個資料結構只能巢狀和被巢狀一次。
求可能出現的不同局面的數量。答案對\(10^9+7\)取模。
\(N\le 300,B_i<A_i<10^9\)

資料範圍很小,\(DP\)可行。
因為\(B_i\le A_i\),所以一個數據結構不能巢狀自己。
因為要執行到無法再執行為止,所以巢狀的資料結構數是固定並且最大

的。
將一個數據結構拆成\(A_i,B_i\)兩個點,從大到小排序,保證列舉到的\(A_i\)能被前面列舉的\(B_i\)巢狀。因為\(A_i=B_j\)時不能巢狀,所以相等時\(A\)\(B\)前面。

\(f[i][j][k]\)表示前\(i\)個點,有\(j\)\(B\)點可選(沒有巢狀\(A\)點)。

  • 若第\(i\)個是\(B\)點,則方案數不變,可選的\(B\)\(+1\)

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

  • 若第\(i\)個是\(A\)點,則可以分三種情況討論:
    • 不巢狀:
      如果\(A_i\)不被巢狀,那麼\(A_i\)之前的所有\(B\)
      點必須在後面被巢狀,否則,一定可以把\(A_i\)和前面的某一個\(B\)點巢狀,使得巢狀數量\(+1\),說明當前的巢狀數沒有達到最大。
      \(f[i][j][k]\)表示在\(j\)個可選的\(B\)點中,有\(k\)個是必選\((k\le j)\)
      所以,當前可選的\(j\)個點全部變為必選,方案數不變。

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

    • 被非必選點巢狀:

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

    • 被必選點巢狀:
      因為必選點被可選點包含,所以\(k-1\)的同時,也要\(j-1\)

    \[f[i][j-1][k-1] += f[i-1][j][k] * k \]

統計答案時,如果有必選點剩餘則不合法。
最後答案即為\(\sum \limits_{j=1} ^{n} f[n*2][j][0]\)

用滾動陣列可以消去第一維,不要忘記把\(f[i%2]\)清零。

程式碼如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MogeKo qwq
using namespace std;

const int maxn = 305;
const int mod = 1e9+7;

int n,x,y,cnt;
long long ans,f[2][maxn][maxn];

struct node {
	int w,type;
	bool operator < (const node &N)const {
		return w > N.w || (w == N.w && type > N.type);
	}
} d[maxn<<1];


int main() {
	freopen("ds.in","r",stdin);
	freopen("ds.out","w",stdout);
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) {
		scanf("%d%d",&x,&y);
		d[++cnt] = (node) {x,1};
		d[++cnt] = (node) {y,0};
	}
	sort(d+1,d+cnt+1);
	f[0][0][0] = 1;	
	for(int i = 1; i <= cnt; i++) {
		memset(f[i%2],0,sizeof(f[i%2]));
		for(int j = 0; j <= n; j++) {
			for(int k = 0; k <= j; k++) {
				if(!f[(i-1)%2][j][k]) continue;
				if(!d[i].type)
					(f[i%2][j+1][k] += f[(i-1)%2][j][k]) %= mod;
				else{
					(f[i%2][j][j] += f[(i-1)%2][j][k]) %= mod;
					if(j) (f[i%2][j-1][k] += f[(i-1)%2][j][k] * (j-k)) %= mod;
					if(j&&k) (f[i%2][j-1][k-1] += f[(i-1)%2][j][k] * k) %= mod;
				}
			}
		}
	}
	for(int j = 0;j <= n;j++)
		(ans += f[0][j][0]) %= mod;
	printf("%lld",ans);
	return 0;
}