csp模擬 企鵝棋【計數dp】

傳送門

每個點有向左,向右,都可以,三種跳躍屬性。問從起點到終點的,經過每個點一次的方案數。

 

我們要求的就是合法的全排列,滿足起點是第一個,終點是最後一個,任何一個可以到下一個的數量。

我們考慮最後的這個排列,從1開始,對每個數考慮其應該放在哪裏。

我們發現,任何時刻,這樣放出來的連通塊,右端點一定是R或B,左端點一定是L或B。

因爲我們從1~n添加,所以沒有添加的數一定比添加了的數大。如果是右端點,就要到達一個比自己大的,那我只能向右。

反之就是向左。

 

然後我們發現,要產生這樣的限制,只能說明我跟連通塊發生了關係(或者自己成了一個新連通塊)

所以可以設置狀態f[i][j]表示考慮到數i,現在有j個連通塊的方案數。

但是我們發現,起點和終點的位置是確定的,要提出來討論。所以我們設free爲不是起點,終點的連通塊數量。

所以狀態轉移是這樣的:

如果i+1是起點:

其要麼自成一個新連通塊,要麼和一個普通連通塊連在一起。

如果i+1是終點:

其要麼自成一個新連通塊,要麼和一個前面的普通連在一起。

如果都不是:

1:自成一個連通塊

2。和起點連通塊連接。

3。和起點連通塊以及一個普通連通塊連接。

4。和終點連接。

5。和終點連通塊以及一個普通連通塊連接。

6。成爲一個普通塊的右端點。

7。成爲一個普通塊的左端點。

8。連接兩個普通聯通塊。

 

然後就寫吧,,

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
const int mod=1e9+7;
int f[5003][5003];
char ch[5003],n,s,e;
signed main(){
	scanf("%s",ch+1);
	n=strlen(ch+1);s=in;e=in;
	f[0][0]=1;
	for(int i=0;i<=n-2;i++){
		int st;if(i==0)st=0;else st=1;
		for(int j=st;j<=i;j++){
			long long key=f[i][j];if(!key)continue;
			int free=j;
			if(i>=s)free--;if(i>=e)free--;if(free<0)continue;char x=ch[i+1];
			if(i+1==s){
				if(x=='R'||x=='B')f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
				if(x=='L'||x=='B')f[i+1][j]=(f[i+1][j]+key*free)%mod;
			}
			else if(i+1==e){
				f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
				f[i+1][j]=(f[i+1][j]+key*free)%mod;
			}
			else{
				if(x=='R'||x=='B')f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
				if(i+1>s&&(x=='R'||x=='B'))f[i+1][j]=(f[i+1][j]+key)%mod;
				if(i+1>s&&(x=='L'||x=='B')&&j)f[i+1][j-1]=(f[i+1][j-1]+key*free)%mod;
				if(i+1>e&&(x=='L'||x=='B'))f[i+1][j]=(f[i+1][j]+key)%mod;
				if(i+1>e&&(x=='L'||x=='B')&&j)f[i+1][j-1]=(f[i+1][j-1]+key*free)%mod;
				if(x=='R'||x=='B')f[i+1][j]=(f[i+1][j]+free*key)%mod;
				if(x=='L'||x=='B')f[i+1][j]=(f[i+1][j]+free*key)%mod;
				if(free>=2&&(x=='L'||x=='B'))f[i+1][j-1]=(f[i+1][j-1]+key*free%mod*(free-1)%mod)%mod;
			}
		}
	}int ans=0;
	if(n==s){if(ch[n]=='L'||ch[n]=='B')ans=f[n-1][1];}
	else if(n==e)ans=f[n-1][1];
	else if(ch[n]=='L'||ch[n]=='B')ans=f[n-1][2];
	cout<<ans;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章