Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

 | 

2012-06-30

Codeforces Round #127 Div1 A - Clear Symmetry

10:39 |  Codeforces Round #127 Div1 A - Clear Symmetry - kojingharangの日記 を含むブックマーク はてなブックマーク -  Codeforces Round #127 Div1 A - Clear Symmetry - kojingharangの日記  Codeforces Round #127 Div1 A - Clear Symmetry - kojingharangの日記 のブックマークコメント

  • 1 が隣り合わない and 上下左右対称 and 1 の個数が X 個になるように 0 か 1 を NxN グリッドに入れたい。最小の N を求める問題。
  • X ≦ 100
  • X==2 とか配置できんの??と思ったけど真ん中の列の上下に置けばいいのか
  • 真ん中を含む左上の領域を考えて、そこに1を置いて上下左右対称になるように展開すると全体として何個1が増えるかを考える。
// N==3
42
21

4のとこに置くと以下のように1が4つになる
101
000
101

右上の2のとこに置くと以下のように1が2つになる
010
000
010

// N==4
44
44

// N==5
442
442
221
  • そこから 1 が隣り合わないように市松模様の黒のとこにある数字だけ抜き出す。X がその数字の和で表せたら OK。
  • 黒と白で2通り試しながら N を大きくしていくといつか終わる。
  • この抜き出し方でいい証明はできてない
// X==9 N==5 のばあい
 4 
4 2
 2 
→4 4 2 2 じゃ 9 にならないので skip

4 2
 4 
2 1
→4+4+1==9 なので N==5 で OK

// X==3 N==5 のばあい
 4 
4 2
 2 
→4 4 2 2 じゃ 3 にならないので skip

4 2
 4 
2 1
→2+1==3 なので N==5 で OK

  • Accepted
int main() {
	int X;
	
	while(cin>>X) {
		for(int n=1;;n++) {
			//cout<<n<<endl;
			{
				int x = X;
				int n4 = (n-1)*(n-1)/2;
				int n2 = ((n-1)/2 + ((n-1)&1))*2;
				int n1 = 0;
				//cout<<n4<<" "<<n2<<" "<<n1<<endl;
				while(n4-->0 && x>=4) x-=4;
				while(n2-->0 && x>=2) x-=2;
				while(n1-->0 && x>=1) x-=1;
				if(x==0) { cout<<2*n-1<<endl; break; }
			}
			{
				int x = X;
				int n4 = (n-1)*(n-1)/2 + ((n-1)*(n-1)&1);
				int n2 = (n-1)/2*2;
				int n1 = 1;
				//cout<<n4<<" "<<n2<<" "<<n1<<endl;
				while(n4-->0 && x>=4) x-=4;
				while(n2-->0 && x>=2) x-=2;
				while(n1-->0 && x>=1) x-=1;
				if(x==0) { cout<<2*n-1<<endl; break; }
			}
		}
	}
	
	return 0;
}
 |