Forward, march!

题目描述

Jack has become a soldier now. Unfortunately, he has trouble with the drill. Instead of marching beginning with the left foot and then changing legs with each step, as ordered, he keeps repeating a sequence of steps, in which he sometimes makes the wrong steps or — horror of horrors! — stops for a while. For example, if Jack uses the sequence 'right, left, break', when the sergeant yells: 'Left! Right! Left! Right! Left! Right!', Jack first makes a step with the right foot, then one with the left foot, then he is confused and stops for a moment, then again - this time according to the order - starts with the right foot, then uses the left foot, then - to the sergeant's irritation - he stops to catch his breath, to incorrectly start with the right foot again... Marching this way, Jack will make the step that he is supposed to in the given moment in only one third of cases.

When the officers convinced him he should do something about it, Jack decided to modify the basic sequence of steps that he repeats. However, in order not to get too tired, he has decided that the only thing he'll do is adding any number of breaks in any positions of the original sequence (a break corresponds to stopping for the duration of one step). Of course, Jack can't make a step on the same foot twice in a row, if there is no pause between these steps. It is, however, not impossible that the sequence of steps he used so far is incorrect (it would explain a lot, actually).

Help Private Jack! Given the sequence of steps he keeps repeating, calculate the maximal percentage of time that he can spend marching correctly after adding some breaks to his scheme.

输入格式

The first line of input contains a sequence consisting only of characters 'L', 'R' and 'X', where 'L' corresponds to a step with the left foot, 'R' — with the right foot, and 'X' — to a break. The length of the sequence will not exceed 106106 .

输出格式

Output the maximum percentage of time that Jack can spend marching correctly, rounded down to exactly six digits after the decimal point.

题意翻译

题目描述

杰克现在成了一名士兵。不幸的是,他在演习中遇到了麻烦。他没有按照先迈出左脚再不断交换迈脚的顺序前进,而是不断地重复一系列的步骤序列,有时他会做出错误的步骤或者停一会儿。例如,如果杰克使用序列 “右,左,休息”,当中士喊道:“左!右!左!右!左!右!”杰克先用右脚迈出了一步,然后用左脚迈出了一步,然后他感到很迷惑,停了一会儿,然后又一次按照他自己的顺序——用右脚开始,然后用左脚,接着让中士恼怒的是——他又停下来喘口气,又不正确地用右脚开始 …… 这样子行军,杰克会在只有三分之一的时间迈出正确的步伐。

当警官说服他应该改掉这个毛病的时候,杰克决定修改他重复的步骤。然而,为了不太累,他决定他唯一要做的就是在原始序列中的任何位置添加任意数量的中断(中断对应于一步的停顿)。当然,如果这些步骤之间没有停顿,杰克就不能连续的迈出同一只脚。需要注意的是,他目前使用的步骤有可能是不正确的。

帮助士兵杰克!给出他开始时不断重复的步骤,计算出在他计划中增加一些休息时间后他能正确行进的时间占行军时间的最大百分比。

输入格式

输入的第一行包含一个只包含字符 LR 和 X 的序列,其中 L 对应的是左脚的一步,R 代表的是右脚的一步,X 代表一次休息。序列长度不超过 106106。

输出格式

输出杰克能正确行进的最大时间百分比,保留到小数点后六位数。

说明 在第二个例子中,如果我们在 LXRR 序列中增加两次停顿变成 LXXRXR,杰克将这样行军:LXXRXRLXXRXRL…… 而不是 LRLRLRLRLRLRL……,这样他在一半的情况下会走出正确的步伐。如果我们不加任何休息,这个顺序就不正确了——杰克不能连续两次地迈右脚。

感谢 @稀神探女 和 @MaWenXin 提供的翻译。

输入输出样例

输入 #1复制

X

输出 #1复制

0.000000

输入 #2复制

LXRR

输出 #2复制

50.000000

说明/提示

In the second example, if we add two breaks to receive LXXRXR, Jack will march: LXXRXRLXXRXRL... instead of LRLRLRLRLRLRL... and will make the correct step in half the cases. If we didn't add any breaks, the sequence would be incorrect — Jack can't step on his right foot twice in a row.

解题思路:

首先对于给出的串进行一些初步的处理,题目中给出的串不一定是正确的,先将所有不可能的情况补全成可行情况是必要的。

需要注意,这个行走的串是循环的,所以最后一个和第一个其实是连在一起的,需要在前面或者后面加一个停顿。如果前后都是 �R 则将停顿加到最前面,都是 �L 就加到最后面。


由于分母会随着操作进行变动,直接用动态规划求解并不好做,可以考虑先二分出一个答案,然后同构每一步减去这个答案转化成判定性问题。

转化后的问题也就是每一步会减少一个权值,如果匹配成功获得一个单位的权值,求最大权值。

设 ��,�fi,j​ 表示考虑到原来串的第 �i 个位置,且下一个位置上列队中的其它人的动作为 �j,�j 为 00 或者 11,分别表示左和右。

然后考虑转移,对于一个位置,理论上可以在这个位置之前加上任意多个停顿,但是很显然的是一旦加上了超过 11 次就一定不优。所以只考虑加或者不加两种情况即可。

形式化的,有:��,�=���(��−1,¬�+[��=�]−���,��−1,�+[��=¬�]−2×���)fi,t​=max(fi−1,¬t​+[ai​=t]−mid,fi−1,t​+[ai​=¬t]−2×mid)。

前者表示不加,后者则是表示增加一个停顿。

初值是 �0,0=−���,�0,1=0f0,0​=−mid,f0,1​=0。


注意最后的答案需要向上取值。


代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2000000;
int s[MAXN+5],n;
double f[MAXN+5][2],l,r,mid;
/*
0-L
1-R
2-X
*/
string S;
inline double max(double x,double y){
	if(x>y)return x;
	return y;
}
inline bool check(double num){
	f[0][0]=-num;f[0][1]=0;
	for(int i=1;i<=n;i++){
		f[i][0]=max(f[i-1][0]+(s[i]==1)-2.0*num,f[i-1][1]+(s[i]==0)-num);
		f[i][1]=max(f[i-1][1]+(s[i]==0)-2.0*num,f[i-1][0]+(s[i]==1)-num);
	}
	return f[n][1]>=0;
}
int main(){
	cin>>S;
	if(S[0]==S[S.length()-1]&&S[0]=='R')s[++n]=2;
	if(S[0]=='X')s[++n]=2;if(S[0]=='L')s[++n]=0;if(S[0]=='R')s[++n]=1;
	for(int i=1;i<S.length();i++){
		if(S[i]=='X')s[++n]=2;
		if(S[i]=='L'){
			if(S[i-1]=='L')s[++n]=2;
			s[++n]=0;
		}
		if(S[i]=='R'){
			if(S[i-1]=='R')s[++n]=2;
			s[++n]=1;
		}
	}
	if(S[0]==S[S.length()-1]&&S[0]=='L')s[++n]=2;
	l=0;r=100;
	while(r-l>=1e-9){
		mid=(l+r)/2;
		if(check(mid/100))l=mid;
		else r=mid;
	}
	printf("%.6lf",(int)(r*1000000)/1000000.0);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值