[實驗艙 CSP/NOIP新賽制內部挑戰賽5] B.小F的編碼(BFS/DP)
阿新 • • 發佈:2020-11-16
Problem
Solution
-
考慮一個簡化版問題:給定長度為 \(m\) 的字串 \(S\),和一些模式串 \(c_i\),問有多少種方案拼成 \(S\)。
-
思路:設 \(f[i]\) 表示有多少種方案拼成 \(S[1...i]\),那麼有轉移 \(f[i]=\sum_{c_x=S[k...i]} f[k]\),答案就是 \(f[m]\)。具體的,看作有 \(m+1\) 個點,若 \(c_x = S[k...i]\),則在 \(k->i\) 連一條邊,最統計有多少種從 \(0\) 到 \(m\) 的路徑。
題解
設 \(f[i,j]\) 表示第 \(i\) 個字串匹配了 \(j\)
同樣把 \((i,j)\) 這個狀態看成一個點。\((i,j)->(u,v)\) 之間有邊則說明可以將 \(c_u\) 接上去,即滿足:\(S_i[j...len]=S_u[1...v]\)。
注意處理一些細節。初始狀態 \(f[i,0]=1\),最終看是否有 \(f[i,n]=1\)。狀態數 \(O(nL)\),建邊複雜度 \(O(n^2L^2)\),時間複雜度 \(O(n^2L^2)\)。
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h> #define mp make_pair #define fi first #define se second using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return x * f; } typedef pair<int,int> PII; const int N = 57, maxn = N*N; int n,cnt; int head[maxn]; int f[N][N]; char str[N][N]; struct Edge { int next,to; }edge[maxn*maxn]; inline void add(int u,int v) { edge[++cnt] = (Edge)<%head[u],v%>; head[u] = cnt; } bool check(int x,int lx,int y,int ly,int len) { for(int i=0;i<len;++i) if(str[x][lx+i] ^ str[y][ly+i]) return false; return true; } int Getid(PII x) { return x.fi*N + x.se; } PII Getpii(int x) { return mp(x/N, x%N); } void work() { memset(str, 0, sizeof(str)); memset(head, 0, sizeof(head)); cnt = 0; memset(f, 0, sizeof(f)); n = read(); for(int i=1;i<=n;++i) scanf("%s",str[i]+1); for(int i=1;i<=n;++i) { int len = strlen(str[i]+1); for(int j=0;j<=len;++j) { for(int u=1;u<=n;++u) { if(j==0 && i==u) continue; int ulen = strlen(str[u]+1); if(ulen >= len-j) { if(check(i,j+1,u,1,len-j)) { add(Getid(mp(i,j)), Getid(mp(u,len-j))); } } else { if(check(i,j+1,u,1,ulen)) { add(Getid(mp(i,j)), Getid(mp(i,j+ulen))); } } } } } queue<int> q; for(int i=1;i<=n;++i) { int len = strlen(str[i]+1); q.push(Getid(mp(i,0))); f[i][0] = 1; } while(!q.empty()) { int u = q.front(); q.pop(); PII uu = Getpii(u); int x = uu.fi, y = uu.se; for(int i=head[u];i;i=edge[i].next) { int v = edge[i].to; PII vv = Getpii(v); int nx = vv.fi, ny = vv.se; if(!f[nx][ny]) { f[nx][ny] = f[x][y]; q.push(v); } } } bool flag = 0; for(int i=1;i<=n;++i) flag |= f[i][strlen(str[i]+1)]; if(flag) puts("No"); else puts("Yes"); } int main() { int T = read(); while(T--) work(); return 0; } /* 1 2 00 000 No */