Codeforces 135 C. Zero-One

問題

0と1からなる文字列に対して二人が次のようなゲームをする。

  • 手番を交互にもつ
  • 手番のプレイヤーは1つ文字を消す
  • 残りが2文字になったら終了
  • 先手は、残る文字列を最小化し、後手は残る文字列を最大化する


ただし、与えられる文字列には'?'があり、
そこには0または1の好きな文字を当てはめてよい。


結果として残る文字列としてありうるものを全て出力せよ。

制約条件

文字列の長さ≦10^5

方針

先手は1があれば1を消すのが最善。
後手は0があれば0を消すのが最善。
0,1が複数ある場合、最も左にあるものを消すのが最善。


そして、1が0より多かったら11が、0が1より多かったら00が残る。
同数だったら、最も右に何があるかで01が残るか10が残るかが決まる。


文字列の長さが奇数の場合は、先手の手番で終了するので、
カウントが1ずれる。

ソースコード

string in;
int n,zero,one,wild;

void run()
{
	cin>>in;
	n=in.size();
	zero=one=wild=0;
	rep(i,n)if(in[i]=='0')zero++;
	else if(in[i]=='1')one++;
	else wild++;
	
	if(n%2){
		if(zero+wild>one)cout<<"00"<<endl;
		int w=(wild+one-zero-1)/2;
		if(zero+w+1==one+wild-w&&0<=w&&w<=wild){
			int p=n-1;
			bool ok=1;
			for(;p>=0;p--)if(in[p]=='1'||in[p]=='?'&&wild-w>0)break;
			else ok=0;
			if(ok)cout<<"01"<<endl;
			p=n-1;
			ok=1;
			for(;p>=0;p--)if(in[p]=='0'||in[p]=='?'&&w>0)break;
			else ok=0;
			if(ok)cout<<"10"<<endl;
		}
		if(one+wild>zero+2)cout<<"11"<<endl;
	}
	else{
		if(zero+wild>one)cout<<"00"<<endl;
		int w=(wild+one-zero)/2;
		if(zero+w==one+wild-w&&0<=w&&w<=wild){
			int p=n-1;
			bool ok=1;
			for(;p>=0;p--)if(in[p]=='1'||in[p]=='?'&&wild-w>0)break;
			else ok=0;
			if(ok)cout<<"01"<<endl;
			p=n-1;
			ok=1;
			for(;p>=0;p--)if(in[p]=='0'||in[p]=='?'&&w>0)break;
			else ok=0;
			if(ok)cout<<"10"<<endl;
		}
		if(one+wild>zero)cout<<"11"<<endl;
	}
}