arrows blog

解いた問題などを適当に書いていきます。

SRM 663 div2

Easy

問題文

N × Nのボードにそれぞれ英小文字が書いてある.
ある英小文字を好きな英小文字に書き換えることができる.

ボードをチェック模様(ある文字を見たとき、上下左右に隣接する文字が全て異なり、ボードを2つの文字で表現することができる)
にするためには、最小で何回書き換える必要があるか.

制約

  • 2 ≤ N ≤ 20

解法

全探索.
ボード上のマスを(x,y)とすると、(x+y)が奇数になるマスと(x+y)が偶数になるマスに異なる文字を割り当てることがわかる.
その割り当てる文字を全通り試す. ただし、同じ文字を割り当ててはならない.

コード

class ChessFloor {
public:
    int minimumChanges(vector<string> floor) {
	int res = 114514;
	int N = floor.size();
	for(char a = 'a' ; a <= 'z' ; a++){
	    for(char b = 'a' ; b <= 'z' ; b++){
		if(a == b) continue;
		int cnt = 0;
		for(int i = 0 ; i < N ; i++){
		    for(int j = 0 ; j < N ; j++){
			if((i+j)%2 == 0){
			    if(a != floor[i][j]){
				cnt++;
			    }
			}else{
			    if(b != floor[i][j]){
				cnt++;
			    }
			}
		    }
		}
		res = min(res,cnt);
	    }
	}
	return res;
    }
}

Med

問題文

スタートの文字列initialとゴールの文字列targetが与えられる.
この文字列は'A'と'B'で構成されている.

以下の2つの操作ができる.

  • 文字列の末尾に'A'という文字を連結する.
  • 文字列を反転し、末尾に'B'という文字を連結する.

この操作を任意の回数行い、initialからtargetにすることが可能かどうか.

制約

  • 1 ≤ |initial| ≤ 999
  • 2 ≤ |target| ≤ 1000
  • |initial| < |target|

解法

区間DP.

dp[左の区間][右の区間][文字列が逆順かどうか] := 可能かどうか.
targetの状態から、initialの状態へと遷移させる.

余談

実は、targetの状態から、initialの状態へと遷移させるのであれば、
遷移が一意に定まるのでシミュレーションするだけになる.

明らかにこれに気づかないのはヤバいよなぁ…
まぁ区間DPの練習になったしいいか.

コード

int dp[1010][1010][2];

class ABBA {
public:
    int len;
    bool check(int L,int R,int d,string &a,string &b){
	if(d == 0){
	    for(int i = L ; i <= R ; i++){
		if(a[i-L] != b[i]) return false;
	    }
	}else{	    
	    for(int i = R ; i >= L ; i--){
		if(a[R-i] != b[i]) return false;
	    }
	}
	return true;
    }
    
    int solve(int L,int R,int d,string &a,string &b){
	if(R-L+1 == len){
	    return (check(L,R,d,a,b) ? 1 : 2);
	}
	int &res = dp[L][R][d];
	if(res > 0) return res;
	res = 2;
	if(d == 0){
	    if(b[R] == 'A') res = min(res,solve(L,R-1,d,a,b));
	    if(b[R] == 'B') res = min(res,solve(L,R-1,1-d,a,b));
	}else{
	    if(b[L] == 'A') res = min(res,solve(L+1,R,d,a,b));
	    if(b[L] == 'B') res = min(res,solve(L+1,R,1-d,a,b));
	}
	return res;
    }

    string canObtain(string initial, string target) {
	int L = 0,R = target.size()-1;
	memset(dp,0,sizeof(dp));
	len = initial.size();
	return (solve(L,R,0,initial,target) == 1 ?
		"Possible" : "Impossible");
    }
}