2052-Optimal Rest

超良問

問題概要

RXを1/X秒休むという命令とする.
また,その後ろに'.'が付いた場合は前の命令の1/2秒だけ休むとする.
例えばR1..の場合1+1/2+1/4=7/4秒休むことになる.
そして分母に65以上の数が出ることは無く,Xとして用いて良い数は1,2,4,8,16,32とする.
これらの規則にそったある表現が与えらえるので出来るだけ短く,かつ辞書順に早いものを答えろ.
例:R1R2R4→R1..

解法

文字数が小さい場合の動的計画法を行う.
そして文字数が多い場合は必ず"R1.R1.R1.…………"の形を含むので,それをどこに含むのかを全探索する.

実装(C++)

#include <iostream>
using namespace std;

int count(const string &in){
	int back=1;
	int res=0;
	int L=in.size();
	for(int i=0;i<L;i++){
		if(in[i]=='.'){
			res+=back/2;
			back/=2;
		}else if(in[i]=='R'){
			if(in[i+1]=='1'&&i+2<L&&in[i+2]=='6'){
				back=64/16;
				res+=back;i+=2;
			}else if(in[i+1]=='1'){
				back=64/1;
				res+=back;i+=1;
			}else if(in[i+1]=='2'){
				back=64/2;
				res+=back;i+=1;
			}else if(in[i+1]=='4'){
				back=64/4;
				res+=back;i+=1;
			}else if(in[i+1]=='8'){
				back=64/8;
				res+=back;i+=1;
			}else if(in[i+1]=='3'){
				back=64/32;
				res+=back;i+=2;
			}else if(in[i+1]=='6'){
				back=64/64;
				res+=back;i+=2;
			}
		}
	}
	return res;
}
const int k_mod=64*3*2;
string dp[31][k_mod*2];
string d[28]={"R1","R1.","R1..","R1...","R1....","R1.....","R1......","R2","R2.","R2..","R2...","R2....","R2.....","R4","R4.","R4..","R4...","R4....","R8","R8.","R8..","R8...","R16","R16.","R16..","R32","R32.","R64"};
int d_len[28];
int d_val[28];
string pre_ans[k_mod*2];
int main() {
	int n;
	for(int i=0;i<28;i++){
		d_len[i]=d[i].size();
		d_val[i]=count(d[i]);
	}
	for(int i=0;i<31;i++){
		for(int j=0;j<k_mod*2;j++){
			if(i==0&&j==0){
			}else{
				if(dp[i][j]=="")continue;
			}
			for(int k=0;k<28;k++){
				if(j+d_val[k]<k_mod*2&&i+d_len[k]<31){
					if(dp[i+d_len[k]][j+d_val[k]]==""){
						dp[i+d_len[k]][j+d_val[k]]=dp[i][j]+d[k];
					}else{
						if(dp[i+d_len[k]][j+d_val[k]]>dp[i][j]+d[k])dp[i+d_len[k]][j+d_val[k]]=dp[i][j]+d[k];
					}
				}
			}
		}
	}
	int q=0;
	for(int i=1;i<k_mod*2;i++){
		for(int j=0;j<31;j++){
			if(dp[j][i]!=""){
				pre_ans[i]=dp[j][i];
				q=max(j,q);
				break;
			}
		}
	}
	for(cin>>n;n--;){
		string in;
		cin>>in;
		int cnt=count(in);
		int pcnt=cnt/k_mod;
		cnt%=k_mod;
		if(pcnt>0){
			cnt+=k_mod;
			pcnt-=1;
		}
		string res="";
		if(cnt!=0){
			res=pre_ans[cnt];
		}
		string pres="";
		for(int i=0;i<pcnt*k_mod/96;i++){
			pres+="R1.";
		}
		string ans=pres+res;
		int L=res.size();
		for(int i=0;i<L;i++){
			if(res[i]=='R'){
				ans=min(ans,res.substr(0,i)+pres+res.substr(i));
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}