1. 程式人生 > >【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; }