Dan is playing a game with Ben. Ben gives Dan a long string S, and Dan needs to compress S to a list or short strings: s[1], s[2], ..., s[N]. S only contains lowercase letters. Each s[i] can contain lowercase letters and digits, but only digits between i+1 and N, inclusive, are allowed for s[i]. For example, when N = 4, allowed digits for s[2] will be '3' and '4'.
In order to decompress such a list of strings into a single string, we'll apply string decompress algorithm for each string one by one, in reverse order (from s[N] to s[1]). The decompressing algorithm for a string is easy: just replace each digit in the string by the corresponding decompressed string with that digit as index. That is to say, for digit i in the string, it will be replaced by the decompressed string s[i]. Because we are applying decompressing algorithm in reverse order, s[i] will always be decompressed before it is used to replace a digit in other strings. When all the strings are decompressed, the decompressed string of s[1] will be the final result. If the decompressing result is S, we say S can be compressed to this list of strings.
Now Ben decides the number of short strings Dan can use (N), as well as the length limit for each short string. Dan needs to decide whether it is possible to compress S to N short strings under this limit.
Input
There are multiple test cases (no more than 150). For each case, there will be three lines. The first line gives an integer N (1 ≤ N ≤ 4), which is the number of short strings Dan can use. The second line gives N integers L[1], ... L[N] (1 ≤ L[i] ≤ 4), which means the length of string s[i] should be at most L[i]. The third line gives the string S. The length of S will be between 1 and 500, inclusive. S will only contain lowercase letters.
Output
For each case, if it is possible to compress S into N strings and the length of each string is no more than the limit, output "Yes". Otherwise, output "No".
Sample Input
1 1 aa 4 4 4 4 4 ttttttttttttttt
Sample Output
No Yes
Author: HANG, Hang
Contest: The 2011 ACM-ICPC Asia Dalian Regional Contest
Analysis:
首先,最后的待压缩串的信息只直接和s[1]关联,但是要确定s[1]串的话,又必须要有后面的所有串的信息。
这样搜索的顺序,必须要从后面的串开始,但是这样有没有直接的压缩串的信息,所以剪枝很麻烦。
我的想法就是要在尽量少用剪枝的情况下,通过对搜索结构的优化来达到目的。
权衡之后,我决定采取外层第一曾dfs()仅确定长度和扩展位置,堆每一组合的模糊解,第二层再check()判断其是否有真的合法的方法。
两条剪枝。
1.可行性剪枝:对外层dfs(),记录当前最长的分解串长度。
2.改变搜索顺序:对有解的情况下尽可能发现正解。
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
const int N = 4, M = 500, L = 4;
char S[M];
int len;
int s[N][L];
int _l[N], l[N], ll[N];
int n;
const int Normal = -1;
bool C[N];
int st[N];
bool check()
{
RST(C);
C[n - 1] = true, st[n - 1] = 0;
DWN(k,n, 1)
if (C[k])
{
int p = st[k];
REP(i, l[k])
{
#define j s[k][i]
if (j == Normal)
{
++p;
}
else
{
if (C[j])
{
REP(ii, ll[j])
{
if (S[p + ii] != S[st[j] + ii]) return false;
}
}
else
{
C[j] = true, st[j] = p;
}
p += ll[j];
}
}
}
return true;
}
inline bool dfs1(int, int);
inline bool dfs2(int, int, int);
bool dfs2(int i, int k, int max_ll)
{
if (i == l[k])
{
ll[k] = 0;
REP(i, l[k])
ll[k] += s[k][i] == Normal ? 1 : ll[s[k][i]];
return dfs1(k + 1, max(max_ll, ll[k]));
}
else
{
DWN_N(s[k][i], k, -1)
{
if (dfs2(i + 1, k, max_ll)) return true;
}
}
return false;
}
bool dfs1(int k = 0, int max_ll = 1)
{
int t = max_ll;
FOR(i, k, n) t *= _l[i];
if (t < len) return false;
if (k == n)
{
return ll[k - 1] == len && check();
}
else
{
DWN_1_N(l[k], _l[k], 0)
{
if (dfs2(0, k, max_ll)) return true;
}
}
return false;
}
int main()
{
while (scanf("%d", &n) != EOF)
{
DWN(i, n, 0) scanf("%d", &_l[i]);
getchar();
scanf("%s", S);
len = strlen(S);
reverse(S, S + len);
puts(dfs1() ? "Yes" : "No");
}
return 0;
}