Packmen ( 二分答案 )

E. Packmen
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

A game field is a strip of 1 × n square cells. In some cells there are Packmen, in some cells — asterisks, other cells are empty.

Packman can move to neighboring cell in 1 time unit. If there is an asterisk in the target cell then Packman eats it. Packman doesn't spend any time to eat an asterisk.

In the initial moment of time all Packmen begin to move. Each Packman can change direction of its move unlimited number of times, but it is not allowed to go beyond the boundaries of the game field. Packmen do not interfere with the movement of other packmen; in one cell there can be any number of packmen moving in any directions.

Your task is to determine minimum possible time after which Packmen can eat all the asterisks.

Input

The first line contains a single integer n (2 ≤ n ≤ 105) — the length of the game field.

The second line contains the description of the game field consisting of n symbols. If there is symbol '.' in position i — the cell i is empty. If there is symbol '*' in position i — in the cell i contains an asterisk. If there is symbol 'P' in position i — Packman is in the cell i.

It is guaranteed that on the game field there is at least one Packman and at least one asterisk.

Output

Print minimum possible time after which Packmen can eat all asterisks.

Examples
Input
Copy
7
*..P*P*
Output
3
Input
Copy
10
.**PP.*P.*
Output
2
Note

In the first example Packman in position 4 will move to the left and will eat asterisk in position 1. He will spend 3 time units on it. During the same 3 time units Packman in position 6 will eat both of neighboring with it asterisks. For example, it can move to the left and eat asterisk in position 5 (in 1 time unit) and then move from the position 5 to the right and eat asterisk in the position 7 (in 2 time units). So in 3 time units Packmen will eat all asterisks on the game field.

In the second example Packman in the position 4 will move to the left and after 2 time units will eat asterisks in positions 3 and 2. Packmen in positions 5 and 8 will move to the right and in 2 time units will eat asterisks in positions 7 and 10, respectively. So 2 time units is enough for Packmen to eat all asterisks on the game field.


题意

现在有大小为1*n的一条路,路由一个个点构成,‘.’表示该点为空,‘*’表示该点有食物,‘P’表示该点有一个人,每个人可以朝任意方向走,走一格花费1个单位的时间,保证至少有一个人,至少有一个食物,求人把所以u食物都吃光的最小时间(人走到食物的那点就表示把食物吃了,且吃食物不花费时间)。


思路

知道路的总长n,我们可以知道答案肯定落在[1,2*n]的区间内(其实答案肯定小于1.5n,保险方便起见,取最大为2*n好了)。所以我们可以在这个区间内二分答案,如过知道答案,我们就可以去判断在这个答案下人能不能把食物全部吃光,如果可以我们就往值更小的范围内去二分([l,mid-1]),反之,往值更大的范围内去二分([mid+1,r])。


如何根据当前已知的时间m去判断在这个时间内人能否吃完食物:

从左往右遍历路:

1. 如果先遍历到一个点为‘*’,且前面没P,那么把这点的位置存下来,如果这个前面还有‘*’,就不用存了,只要存位置最小的那个‘*’就OK了。


2. 如果遍历到一个点为‘P’,设位置为i:

a. 如果P前面没有食物‘*’,那么到i+m的这段路上就不用考虑了,因为肯定能被这个P吃掉,当然,要注意一点,如果这段路上还有点为P,那么就从这个P开始,而不是i+m开始,因为这个P肯定能走的更远,而直接从i+m开始的话会把这个忽略掉,就会造成损失(就不是最优走法了)。


b. 如果P前面有食物‘*’,如果P在m时间内走不到前面食物的那点,那m肯定太小了,即不可能在m时间内吃完所有食物。如果可以,那就要考虑2种情况:


如果m>=3*x(x表示当前P到最前面还没被吃掉的食物的距离),那么肯定是往前走吃掉那个再回来。


如果m<3*x,那么先往后走再回去刚刚好吃掉那个,这样才能保证往后走尽可能多的距离。


假设最远能到tmp这个点,那么到tmp的这段路上就不用考虑了,因为肯定能被这个P吃掉,当然,同样也要注意一点,如果这段路上还有点为P,那么就从这个P开始。


这样就是最优走法。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <functional>
#include <algorithm>
using namespace std;

const int MAX = 1e5 + 100;

int n;
char str[MAX];

bool judge(int m)
{
	int pos1=-1;//最前面还没被吃掉的食物的位置
	for(int i=0;i<n;i++)
	{
		if(str[i]=='*')
		{
			if(pos1==-1)
				pos1=i;
		}
		if(str[i]=='P')
		{
            //前面没有还没被吃掉的食物
			if(pos1==-1)
			{
				pos1=-1;
				int j;
				for(j=i+1;j<=i+m;j++)
				{
					if(str[j]=='P')
					{
						break;
					}
				}
				i=j-1;
			}
			//前面还有没被吃掉的食物
			else
			{
				if(i-pos1>m)
					return false;
                int tmp;
                if(m>=3*(i-pos1))
                {
                    tmp=pos1+m-(i-pos1);
                    tmp=max(tmp,i);
				}
				else
				{
                    tmp=i+(m-(i-pos1))/2;
				}
                pos1=-1;
				if(tmp>i)
				{
					int j;
					for(j=i+1;j<=tmp;j++)
					{
						if(str[j]=='P')
						{
							break;
						}
					}
					i=j-1;
				}
				else
					i=tmp;
				continue;
			}
		}
	}
	if(pos1!=-1)
		return false;
	return true;
}

int main()
{
	scanf("%d",&n);
	scanf("%s",str);
	int len=strlen(str);
	int l=1,r=2*n;
	int ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(judge(mid)==true)
		{
			r=mid-1;
			ans=mid;
		}
		else
		{
			l=mid+1;
		}
	}
	printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值