UVA 12378 Ball Blasting Game

Ball Blasting Game

Morteza is playing a ball blasting game. In this game there is a chain of different colored balls. He is expected to explode as many balls as possible by aligning same-colored balls and making a sequence of them. To align balls, he can aim and shoot a new ball into a position in the chain, thus adding it there. If the new ball makes a sequence of two or more same-colored balls with its immediate neighbors, then the sequence blows up breaking the chain up into two parts. The two sections draw together to reform a single chain. Again, if the colors of the newly aligned balls (on joining ends of the two sections) match, the entire run of the suit explodes. New explosions ensue as long as joining sections bear new matches.

For instance, consider a chain symbolized in the string "GGGBWWRRWRR", with each letter representing the color of the corresponding ball in the chain. The train of balls therefore is composed of 6 sequences in 4 colors. Here, a ball can be added in 12 different positions. Shooting a red ball between the two middle red balls triggers two successive explosions which leave the chain "GGGBRR".

Morteza reaches a challenge stage in which he has only one ball to shoot but the color of which he can choose. He may not advance to the next stage unless he takes a shot that sets off the largest possible number of explosions. He has to replay all through this repetitive stage should he fail and needs your help in finding the largest possible number of successive explosions to save him a great deal of suffering.

Input

The first line of input contains an integer T≤100 denoting the number of test-cases. Each test-case is represented by a single line containing a string of upper case letters ('A'-'Z') of size of at most 100,000.

Output

For each test-case, output on a single line the maximum possible number of explosions.

Sample Input

Sample Output

3

GGGBWWRRWRR

XAABCBAXAAAA

CCC

2

4

1


【题目大意】

给定一个字符串,向某个位置插入一个字符C使得两个或多个字符C相邻,然后消除这些字符,消除后得到左右两个新字符串,连接两个新字符串,如果连接处是两个或多个相同的字符,则同样消除掉,以此类推

【题解】

把给定的字符串进行预处理,相邻多个相同的字符合并成一个字符

如GGGBWWRRWRR合并成GBWRWR

XAABCBAXAAA合并成XABCBAXA

然后就转化成求最长回文子串问题,

那么怎么求最长回文子串?o(n^2)的算法显然不行,那么需要小于n^2的算法

百度得到Manacher算法

这篇博文讲的不错

http://blog.163.com/zhaohai_1988/blog/static/2095100852012716105847112/

他的代码加了些注释会好理解些

#include<vector>
#include<iostream>
using namespace std;

const int N=300010;
int n, p[N];
char s[N], str[N];

#define _min(x, y) ((x)<(y)?(x):(y))

void kp()
{
    int i;
    int mx = 0;
    int id;
    for(i=n; str[i]!=0; i++)//清除n后边多余的部分 
        str[i] = 0; //没有这一句有问题。。就过不了ural1297,比如数据:ababa aba
    for(i=1; i<n; i++)
    {
        if( mx > i )
            p[i] = _min( p[2*id-i], p[id]+id-i );
			//因为是从左往右扫描的这里i>id, 2*id-i是i关于id的对称点,该对称点在id的左端 
			//p[id]+id是描述中的mx,即id向右延伸的端点位置
			//显然向右延伸是可能超出mx的,所以要有下边的for循环 
        else
            p[i] = 1;
        for(; str[i+p[i]] == str[i-p[i]]; p[i]++);
        
        if( p[i] + i > mx )//更新mx与id,因为mx是向右延伸的最大长度,所以实时更新 
        {
            mx = p[i] + i;
            id = i;
        }
    }
}

void init()//处理字符串
{
 int i, j, k;
 str[0] = '$';
 str[1] = '#';
 for(i=0; i<n; i++)
 {
  str[i*2+2] = s[i];
  str[i*2+3] = '#'; 
 }
 n = n*2+2;
 s[n] = 0;
}

int main()
{
 int i, ans;
 while(scanf("%s", s)!=EOF)
 {
  n = strlen(s);//n为给定字符串s的长度 
  init();
  kp();
  ans = 0;
  for(i=0; i<n; i++)
   if(p[i]>ans)//寻找最大的长度ans 
    ans = p[i];
  printf("%d\n", ans-1);
 }
 return 0;
}


本题代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#define LEN 1000000
using namespace std;
int len,p[LEN],ans;
char s[LEN],GivenStr[LEN];

void init()
{
	memset(s,0,sizeof(s));
	memset(p,0,sizeof(p));
	s[0]='$';
	s[1]='#';
	len=1;
	ans=0;
	
	getchar();
	scanf("%s",GivenStr);
	int lenGiven=strlen(GivenStr);
	for (int i=0;i<lenGiven;i++)
	{
		if (GivenStr[i]==GivenStr[i+1]) continue;
		s[++len]=GivenStr[i];
		s[++len]='#';
	}
}

void LPS()
{
	int id=1,mx=0;
	for (int i=1;i<len;i++)
	{
		if (mx>i)
			p[i]=min(p[2*id-i],mx-i);
		else
			p[i]=1;
		
		while (s[i+p[i]]==s[i-p[i]]) p[i]++;
		
		if (p[i]+i>mx)
		{
			mx=p[i]+i;
			id=i;
		}
		ans=max(ans,p[i]);
	}
}

void out()
{
	printf("%d\n",ans/2);
}

int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		init();
		LPS();//Longest Palindromic Substring
		out();
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值