天天看點

【NOIP2018模拟賽2018.10.3】track

題目

【NOIP2018模拟賽2018.10.3】track
【NOIP2018模拟賽2018.10.3】track

題解

–開始以為和那個什麼括号比對一樣,結果要判重,(QAQ)

結果其實是kmp字元串比對

設f[i][j][k]:第i秒時,高度為j,成功比對第k個的方案數

狀态轉移方程式

if(s[k]==‘U’){

f[i+1][j+1][k+1]=(f[i+1][j+1][k+1]+f[i][j][k])%mod;

if(j)f[i+1][j-1][fail[k][0]]=(f[i+1][j-1][fail[k][0]]+f[i][j][k])%mod;

}

else{

f[i+1][j+1][fail[k][1]]=(f[i+1][j+1][fail[k][1]]+f[i][j][k])%mod;

if(j)f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k])%mod;

}

f[i+1][j+1][l]=(f[i+1][j+1][l]+f[i][j][l])%mod;

if(j)f[i+1][j-1][l]=(f[i+1][j-1][l]+f[i][j][l])%mod;

其中fail[k][0]表示用D比對失敗時可以滿足的字首是多長

fail[k][1]表示用U比對失敗時可以滿足的字首是多少

剩下的就是kmp處理fail數組,像我一樣的蒟蒻還是隻有手算模拟

好像也可以用暴力

不管了

反正就是玄學

代碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=205;
const int mod=1000000007;

int t;
char s[MAXN];
int l;
long long f[MAXN][MAXN][MAXN];
int next[MAXN];
int fail[MAXN][2];

void calc(){
	int k=0;
	for(int i=1;i<l;i++){
		while(k&&s[k]!=s[i])
			k=next[k];
		if(s[k]==s[i])
			k++;
		next[i+1]=k;
	}
	fail[0][s[0]=='U']=1;
	for(int i=1;i<=l;i++){
		k=i;
		while(k&&s[k]!='U')
			k=next[k];
		fail[i][1]=k+1;
		if(!k&&s[0]=='D')
			fail[i][1]=0;
		k=i;
		while(k&&s[k]!='D')
			k=next[k];
		fail[i][0]=k+1;
		if(!k&&s[0]=='U')
			fail[i][0]=0;
	}
}

int main(){
//	freopen("track.in","r",stdin);
//	freopen("track.out","w",stdout);
	cin>>t;
	cin>>s;
	l=strlen(s);
	calc();
	f[0][0][0]=1;
	for(int i=0;i<t;i++)
		for(int j=0;j<=min(i,t-i);j++){
			for(int k=0;k<l;k++){
				if(s[k]=='U'){
					f[i+1][j+1][k+1]=(f[i+1][j+1][k+1]+f[i][j][k])%mod;
					if(j)
						f[i+1][j-1][fail[k][0]]=(f[i+1][j-1][fail[k][0]]+f[i][j][k])%mod;
				}
				else{
					f[i+1][j+1][fail[k][1]]=(f[i+1][j+1][fail[k][1]]+f[i][j][k])%mod;
					if(j)
						f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k])%mod;
				}
			}
			f[i+1][j+1][l]=(f[i+1][j+1][l]+f[i][j][l])%mod;
			if(j)
				f[i+1][j-1][l]=(f[i+1][j-1][l]+f[i][j][l])%mod;
		}
	cout<<f[t][0][l];
	return 0;
}