Codeforces 132 D. Constants in the language of Shakespeare

問題

二進数を、
a1+a2+…+amという形で表したい。
ただしここで、aiはすべて±2^xという形をしているものとする。


与えられた二進数を、上の形で表すために必要な最小の項の数および、
その和の形を具体的に一例出力せよ。

制約条件

二進数の桁数≦10^6

方針

DP+経路復元。


1が連続するところは引き算で作れる。
11111000 = 2^8 - 2^3のように。


今の桁を引き算で作っているか、足し算で作っているかのフラグと桁数を状態として、
dp[pos][flag]を、桁数までを作り、現在の状態が足し算or引き算で作っているときの最小コストとする。
これを更新していくO(n)のDPで解ける。


更新の仕方は下のような感じ。


足し算で作っているときは、1が出てきたら、1を足し算で作る(項数1)か、
引き算で作る(項数2)選ぶことができる。
足し算で作っているときに0が出てきたら、コスト0で作れる。


引き算で作っているときは、1が出てきたらコスト0で作れる。
もしくは、引き算で作っているのをコスト0で(最初に終了分のコストもとってあるので)終了することができる。
引き算で作っているときに0が出てきたら、コスト1かかる。

ソースコード

int dp[1000000][2],prev[1000000][2];

void run()
{
	string in; cin>>in;
	int n=in.size();
	rep(i,n+1)rep(j,2)dp[i][j]=inf;
	dp[0][0]=0;
	rep(i,n){
		if(in[i]=='1'){
			if(dp[i+1][1]>dp[i][1])dp[i+1][1]=dp[i][1],prev[i+1][1]=1;
			if(dp[i+1][0]>dp[i][1])dp[i+1][0]=dp[i][1],prev[i+1][0]=1;
			if(dp[i+1][1]>dp[i][0]+2)dp[i+1][1]=dp[i][0]+2,prev[i+1][1]=0;
			if(dp[i+1][0]>dp[i][0]+1)dp[i+1][0]=dp[i][0]+1,prev[i+1][0]=0;
		}
		else{
			if(dp[i+1][1]>dp[i][1]+1)dp[i+1][1]=dp[i][1]+1,prev[i+1][1]=1;
			if(dp[i+1][0]>dp[i][0])dp[i+1][0]=dp[i][0],prev[i+1][0]=0;
		}
	}
	int s=dp[n][0]>dp[n][1];
	cout<<min(dp[n][0],dp[n][1])<<endl;
	for(int i=n;i>0;i--){
		int p=prev[i][s];
		if(in[i-1]=='1'){
			if(p==1&&s==0)cout<<"-2^"<<n-i<<endl;
			if(p==0&&s==0)cout<<"+2^"<<n-i<<endl;
			if(p==0&&s==1)cout<<"+2^"<<n-i+1<<endl;
		}
		else{
			if(p==1&&s==1)cout<<"-2^"<<n-i<<endl;
		}
		s=p;
	}
}