bzoj4505

    考虑一位一位的枚举答案.
    首先我们知道答案串(设当前枚举到的长度为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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值