考虑一位一位的枚举答案.
首先我们知道答案串(设当前枚举到的长度为L)与原串1到L,n-L+1到n是匹配的(这个性质很重要).
我们设f[i]表示从i开始长度为L的子串能不能和1-L匹配,每次L变化时首先更新一下f[i].
对于当前L,我们暂时把所有f为true的状态存入一个队列.然后我们考虑1-L一共有多少问号.
我们考虑爆搜每一个问号是什么颜色,然后对当前队列中的元素进行检查,去除不满足的元素然后继续搜下一个问号.
(当出现队列中最后一个元素不是n-L+1或者两个元素之差大于L时当前状态失败.)
(元素i的意思是从i位置开始覆盖一次).
然后将所有问号都搜完之后就可以return true.
如果搜索的结果是true,说明当前就是合法的方案了,返回即可.否则L++继续判断.
首先我们知道答案串(设当前枚举到的长度为L)与原串1到L,n-L+1到n是匹配的(这个性质很重要).
我们设f[i]表示从i开始长度为L的子串能不能和1-L匹配,每次L变化时首先更新一下f[i].
对于当前L,我们暂时把所有f为true的状态存入一个队列.然后我们考虑1-L一共有多少问号.
我们考虑爆搜每一个问号是什么颜色,然后对当前队列中的元素进行检查,去除不满足的元素然后继续搜下一个问号.
(当出现队列中最后一个元素不是n-L+1或者两个元素之差大于L时当前状态失败.)
(元素i的意思是从i位置开始覆盖一次).
然后将所有问号都搜完之后就可以return true.
如果搜索的结果是true,说明当前就是合法的方案了,返回即可.否则L++继续判断.
考虑一个剪枝,当L + L >= n后,就可以直接用s[i]与s[n - L + i]来更新ans[i]了.
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
int queue[3010][3010],stack[3010],top = 0,num[3010];
int n,L,T,All;
char Ans[3010],s[3010];
bool f[3010];
bool check(char x,char y) {return (x == y || x == '*' || y == '*');}
bool dfs(int x) {
if(queue[x][num[x]] < n - L + 1) return false;
for(int i = 1;i < num[x];i ++)
if(queue[x][i + 1] - queue[x][i] > L)
return false;
if(x == top) return true;
Ans[stack[x + 1]] = 'R';num[x + 1] = 0;
for(int i = 1;i <= num[x];i ++)
if(check(s[queue[x][i] + stack[x + 1] - 1],'R'))
queue[x + 1][ ++num[x + 1]] = queue[x][i];
if(dfs(x + 1)) return true;
Ans[stack[x + 1]] = 'G';num[x + 1] = 0;
for(int i = 1;i <= num[x];i ++)
if(check(s[queue[x][i] + stack[x + 1] - 1],'G'))
queue[x + 1][ ++num[x + 1]] = queue[x][i];
if(dfs(x + 1)) return true;
Ans[stack[x + 1]] = 'B';num[x + 1] = 0;
for(int i = 1;i <= num[x];i ++)
if(check(s[queue[x][i] + stack[x + 1] - 1],'B'))
queue[x + 1][ ++num[x + 1]] = queue[x][i];
return dfs(x + 1);
}
int main() {
scanf("%d",&T);
while(T --)
{
All = 0;
bool rev = false;
scanf("%s",s + 1);
n = strlen(s + 1);
for(int i = 1;i <= n;i ++)
if(s[i] == '*')
All ++;
for(int i = 1;i <= n / 2;i ++)
if(s[i] == '*')
All -= 2;
if(All < 0) reverse(s + 1,s + n + 1),rev = true;
for(int i = 1;i <= n;i ++)
f[i] = true,Ans[i] = s[i];
top = 0;
for(L = 1;L <= n;L ++)
{
for(int i = 1;i <= n - L + 1;i ++)
if(f[i] && check(s[L],s[i + L - 1]) == false)
f[i] = 0;
if(L + L >= n)
{
if(f[n - L + 1] == false) continue;
for(int i = 1;i <= L;i ++)
Ans[i] = s[i];
for(int i = 1;i <= L;i ++)
if(s[i] == '*')
Ans[i] = s[n - L + i];
break;
}
else
{
if(s[L] == '*') stack[ ++top] = L;
num[0] = 0;
for(int i = 1;i <= n - L + 1;i ++)
if(f[i])
queue[0][ ++num[0]] = i;
if(dfs(0)) break;
}
}
if(rev == true) reverse(Ans + 1,Ans + L + 1);
for(int i = 1;i <= L;i ++)
printf("%c",((Ans[i] == '*') ? 'R' : Ans[i]));
printf("\n");
}
return 0;
}