Problem:
You have a board with height two and width
W
.
The board is divided into 1x1 cells.
Each row of the board is numbered 1 and 2 from top to bottom and each column is numbered 1 to
W
from left to right.
We denote a cell at the
i
-th row in the
j
-th column by
(i, j)
.
Initially, some checkers are placed on some cells of the board.
Here we assume that each checker looks the same.
So we do not distinguish each checker.
You are allowed to perform the following operations on the board:
Square rotation: Choose a 2x2 square on the board. Then move checkers in the 2x2 square such that the checkers rotate their position in the square by 90 degrees in either clockwise or counterclockwise direction.
Triangular rotation: Choose a set of cells on the board that form a triangle. Here, we call a set of cells triangle if it is formed by removing exactly one cell from a 2x2 square. In the similar manner with the square rotation, rotate checkers in the chosen triangle in either clockwise or counterclockwise direction.
The objective in this problem is to transform the arrangement of the checkers into desired arrangement by performing a sequence of rotation operations.
The information of the initial arrangement and the target arrangement are given as the input. For the desired arrangement, one of the following is specified for each cell
(i, j)
: i. cell
(i,j)
must contain a checker, ii. cell
(i,j)
must not contain a checker, or iii. there is no constraint for cell
(i, j)
.
Compute the minimum required number of operations to move the checkers so the arrangement satisfies the constraints and output it.
Input
The input is formatted as follows.
W
s_{11}s_{11}...s_{1W}
s_{21}s_{21}...s_{2W}
t_{11}t_{11}...t_{1W}
t_{21}t_{21}...t_{2W}
The first line of the input contains an integer
W
(
2 \leq W \leq 2,000
), the width of the board. The following two lines contain the information of the initial arrangement. If a cell
(i, j)
contains a checker in the initial arrangement,
s_{ij}
is
o
. Otherwise,
s_{ij}
is
.
. Then an empty line follows. The following two lines contain the information of the desired arrangement. Similarly, if a cell
(i, j)
must contain a checker at last,
t_{ij}
is
o
. If a cell
(i, j)
must not contain a checker at last,
t_{ij}
is
.
. If there is no condition for a cell
(i, j)
,
t_{ij}
is
*
.
You may assume that a solution always exists.
Output
Output the minimum required number of operations in one line.
Sample Input 1
3
.oo
o..

o.o
o..
Output for the Sample Input 1
1
Sample Input 2
5
.o.o.
o.o.o

o.o.o
.o.o.
Output for the Sample Input 2
3
Sample Input 3
4
o.o.
o.o.

.*.o
.o.*
Output for the Sample Input 3
4
Sample Input 4
20
oooo.....ooo......oo
.o..o....o..oooo...o

...o*.o.oo..*o*.*o..
.*.o.o.*o*o*..*.o...
Output for the Sample Input 4
25
Sample Input 5
30
...o...oo.o..o...o.o........o.
.o.oo..o.oo...o.....o........o

**o.*....*...*.**...**....o...
**..o...*...**..o..o.*........
Output for the Sample Input 5
32

Submitted solutions:

code_snippet: // AOJ #2628 Rotation Game
// 2025.3.26

#include <bits/stdc++.h>
using namespace std;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

char temp[20005];
string Cins() { // 文字列の入力　スペース以下の文字で入力終了
    char *s = temp;
	do *s = gc();
	while (*s++ > ' ');
	*(s-1) = 0;
    string input(temp); // 文字配列からstringを作成
    return input;
}

void Cout(int n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

const int INF = 1e9;
int n;
string s[2], t[2];
int dp[2005][8010];

inline bool same(char x, char y) { return x == y || x == '*'; }
inline void ckmin(int &x, int y) { if (x > y) x = y; }

int dfs(int i, int c) {
    if (i == n) return (c == 0 ? 0 : INF);

    int &res = dp[i][c+4000];
    if (res != -1) return res;
    res = INF;

    if (c == 0 && i + 1 < n) {
        char a = s[0][i], b = s[0][i+1], g = s[1][i+1], d = s[1][i];
        char A = t[0][i], B = t[0][i+1], C = t[1][i+1], D = t[1][i];
        if (same(A, d) && same(B, a) && same(C, b) && same(D, g))
            ckmin(res, dfs(i + 2, c) + 1);
        if (same(A, b) && same(B, g) && same(C, d) && same(D, a))
            ckmin(res, dfs(i + 2, c) + 1);
    }

    char a = s[0][i], b = s[1][i];
    for (char p : string("o.")) {
        for (char q : string("o.")) {
            if (same(t[0][i], p) && same(t[1][i], q)) {
                int x = 0, y = 0;
                if (a != p) {
                    if (a == 'o') x++;
                    else y++;
                }
                if (b != q) {
                    if (b == 'o') x++;
                    else y++;
                }
                int etrc = (x == 1 && y == 1 && c == 0) ? 1 : 0;
                int nc = c + x - y;
                ckmin(res, etrc + abs(nc) + dfs(i + 1, nc));
            }
        }
    }
    return res;
}

int main(){
    n = Cin();
    s[0] = Cins(), s[1] = Cins(), gc();
    t[0] = Cins(), t[1] = Cins();
    memset(dp, -1, sizeof(dp));
    Cout(dfs(0, 0));
    return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 66528
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
#define rng(i, l, r) for(int i = int(l); i < int(r); i++)
#define rep(i, n) rng(i, 0, n)
#define sz(v) int(v.size())
#define foa(s, v) for(auto& s : v)
#define all(v) v.begin(), v.end()

#ifdef LOCAL
#define debug(x) cerr << #x << ": " << x << endl
#else
#define debug(x) void(0)
#endif

ostream& operator<<(ostream& os, vector<int> vec) {
	os << "{";
	foa(c, vec) os << c << ", ";
	os << "}";
	return os;
}

ostream& operator<<(ostream& os, vector<vector<int>> vec) {
	os << "{";
	foa(c, vec) os << "\n\t" << c << ", ";
	os << "\n}";
	return os;
}

template <class T>
bool chmax(T& a, T b) {
	return a < b ? a = b, 1 : 0;
}

template <class T>
bool chmin(T& a, T b) {
	return a > b ? a = b, 1 : 0;
}

int n;
void solve() {
	constexpr int wild = -1;
	constexpr int exist = 1;
	constexpr int vacant = 0;

	int wild_counter = 0;
	int end_checker = 0;

	auto input_board = [&]() {
		vector<vector<int>> ret(2, vector<int>(n, vacant));
		foa(row, ret) {
			string s;
			cin >> s;
			rep(i, n) {
				char c = s[i];
				if(c == 'o') {
					row[i] = exist;
				} else if(c == '*') {
					row[i] = wild;
				}
			}
		}
		return ret;
	};

	auto start = input_board();
	auto goal = input_board();

	rep(i, 2) rep(j, n) {
		if(start[i][j] == exist && goal[i][j] == exist) {
			start[i][j] = vacant;
			goal[i][j] = vacant;
		}
	}

	foa(r, goal) foa(c, r) {
		if(c == wild) wild_counter++;
		if(c == exist) end_checker++;
	}

	int mid = n * 2;
	int cmax = mid * 2 + 1;

	constexpr int inf = 4e8;

	vector<int> start_checker(n), goal_checker(n), wilds(n);

	foa(row, start) {
		rep(j, n) {
			if(row[j] == exist) start_checker[j]++;
		}
	}

	foa(row, goal) {
		rep(j, n) {
			if(row[j] == exist) goal_checker[j]++;
			if(row[j] == wild) wilds[j]++;
		}
	}

	vector<vector<int>> dp(n + 1, vector<int>(cmax, inf));
	dp[0][mid] = 0;

	rep(col, n) {
		auto upd = [&](int new_remain, int c, int val) -> void { chmin(dp[c][new_remain + mid], val); };

		rep(checker, cmax) {
			const int pre_value = dp[col][checker];
			if(pre_value >= inf / 2) continue;

			int diff = checker - mid;
			if(diff > 0) {
				rng(use, 0, wilds[col] + 1) { upd(diff + start_checker[col] - goal_checker[col] - use, col + 1, pre_value + abs(diff)); }
			} else if(diff == 0) {
				auto ok_to_rotate = [&]() -> bool {
					if(col + 2 > n) return false;
					auto judge = [&]() -> bool {
						rep(px, 2) rep(py, 2) {
							if((px + py) & 1) {
								if(start[px][col + py] != vacant) return false;
							} else {
								if(start[px][col + py] != exist) return false;
							}
						}

						rep(px, 2) rep(py, 2) {
							if((px + py) & 1) {
								if(goal[px][col + py] == vacant) return false;
							} else {
								if(goal[px][col + py] == exist) return false;
							}
						}

						return true;
					};
					rep(loop, 2) {
						if(judge()) {
							if(loop == 1) {
								swap(start[0], start[1]);
								swap(goal[0], goal[1]);
							}
							return true;
						}
						swap(start[0], start[1]);
						swap(goal[0], goal[1]);
					}
					return false;
				};
				if(ok_to_rotate()) {
					upd(0, col + 2, pre_value + 1);
				}

				const int s = start_checker[col];
				const int g = goal_checker[col];
				const int w = wilds[col];

				if(w == 0) {
					if(s && g) {
						upd(0, col + 1, pre_value + 1);
					} else {
						upd(s - g, col + 1, pre_value);
					}
				} else if(w == 1) {
					int wpos = goal[0][col] == wild ? 0 : 1;
					vector<int> spos(2);
					rep(i, 2) spos[i] = start[i][col];

					if(s == 2) {
						rep(use, w + 1) { upd(diff + s - g - use, col + 1, pre_value); }
					} else if(s == 1) {
						rep(use_wild, 2) {
							if((g == 0 && use_wild == 1 && spos[wpos] != exist) || (g == 1 && use_wild == 0)) {
								upd(diff + s - g - use_wild, col + 1, pre_value + 1);
							} else
								upd(diff + s - g - use_wild, col + 1, pre_value);
						}
					} else {
						rep(use, (w + 1)) { upd(diff + s - g - use, col + 1, pre_value); }
					}
				} else {  // w == 2
					rep(use, w + 1) { upd(diff + s - g - use, col + 1, pre_value); }
				}
			} else {  // diff < 0
				rng(use, 0, wilds[col] + 1) { upd(diff + start_checker[col] - goal_checker[col] - use, col + 1, pre_value + abs(diff)); }
			}
		}
	}

	debug(dp);
	debug(mid);

	rep(i, n+1) rep(c, cmax) {
		int val = dp[i][c];
		if(val < inf / 2) {
			debug(i);
			debug(c-mid);
			debug(val);
		}
	}


	cout << dp.back()[mid] << endl;
}

int main() {
	while(cin >> n && n) solve();
}
accuracy: 1
time_ms: 40
memory_kb: 65948
final_rank: 1

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 4005
#define MAX 4005

enum Which{
	CARRY,
	BORROW,
};


struct Info{
	void set(int arg_carry,int arg_borrow){
		carry = arg_carry;
		borrow = arg_borrow;
	}
	int carry,borrow;
};


struct State{
	State(int arg_tmp_carry,int arg_tmp_borrow,int arg_cost){
		tmp_carry = arg_tmp_carry;
		tmp_borrow = arg_tmp_borrow;
		cost = arg_cost;
	}
	int tmp_carry,tmp_borrow,cost;
};

int W;
int num_L[SIZE],num_R[SIZE];
int must_L[SIZE],free_L[SIZE];
int dp[2005][2][MAX];
char FROM[2][SIZE],TO[2][SIZE];


int main(){

	scanf("%d",&W);

	for(int row = 0; row < 2; row++){
		scanf("%s",FROM[row]);
		for(int col = W-1; col >= 0; col--){
			FROM[row][col+1] = FROM[row][col]; //右に詰める
		}
	}

	for(int row = 0; row < 2; row++){
		scanf("%s",TO[row]);
		for(int col = W-1; col >= 0; col--){
			TO[row][col+1] = TO[row][col]; //右に詰める
		}
	}

	for(int i = 0; i <= W+1; i++){
		num_L[i] = 0;
		num_R[i] = 0;
		must_L[i] = 0;
		free_L[i] = 0;
	}

	//ある列以西にあるコインの数
	num_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(FROM[0][col] == 'o')num_L[col]++;
		if(FROM[1][col] == 'o')num_L[col]++;

		num_L[col] += num_L[col-1];
	}

	//ある列以東にあるコインの数
	num_R[W+1] = 0;
	for(int col = W; col >= 1; col--){
		if(FROM[0][col] == 'o')num_R[col]++;
		if(FROM[1][col] == 'o')num_R[col]++;

		num_R[col] += num_R[col+1];
	}

	//ある列以西にある、必須マスの数
	must_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == 'o')must_L[col]++;
		if(TO[1][col] == 'o')must_L[col]++;

		must_L[col] += must_L[col-1];
	}

	//ある列以西にある、自由マスの数
	free_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == '*')free_L[col]++;
		if(TO[1][col] == '*')free_L[col]++;

		free_L[col] += free_L[col-1];
	}

	for(int col = 0; col <= W+1; col++){
		for(int a = 0; a < 2; a++){
			for(int k = 0; k < MAX; k++){

				dp[col][a][k] = BIG_NUM;
			}
		}
	}

	dp[0][CARRY][0] = 0;


	int carry,borrow;
	int num;

	//★borrowが不適なら遷移しない★
	for(int col = 1; col <= W; col++){

		for(int loop = 0; loop < 2; loop++){

			int start = 0;
			if(loop == 0){ //CARRAY

				borrow = 0;

			}else{ //borrow

				carry = 0;
				start = 1;
			}
			for(int i = start; i < MAX; i++){
					if(dp[col-1][loop][i] == BIG_NUM)continue;

					if(loop == 0){

						carry = i;
					}else{

						borrow = i;
					}

					int A = num_L[col-1]-must_L[col-1]; //拾った数
					if(loop == 0){

						num = A-carry; //置いた数 = 拾った数-carry数
					}else{ //loop == 1

						num = A+borrow; //置いた数 = 拾った数+前借の数
					}

					//例外ケース処理
					if(col <= W-1 && (FROM[0][col+1] == 'o' && FROM[0][col] == '.' && FROM[1][col+1] == '.' && FROM[1][col] == 'o') &&
						TO[0][col+1] != 'o' && TO[0][col] != '.' && TO[1][col+1] != '.' && TO[1][col] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					if(col <= W-1  && (FROM[0][col+1] == '.' && FROM[0][col] == 'o' && FROM[1][col+1] == 'o' && FROM[1][col] == '.') &&
							TO[0][col] != 'o' && TO[0][col+1] != '.' && TO[1][col] != '.' && TO[1][col+1] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					int num_must = 0,num_not = 0;
					int free_match = 0,free_not = 0;

					for(int row = 0; row < 2; row++){
						switch(FROM[row][col]){
						case 'o':
							switch(TO[row][col]){
							case 'o':
								//そのまま
								break;

							case '.':
								num_not++;
								break;

							case '*':
								free_match++;
								break;
							}
							break;


						case '.':
							switch(TO[row][col]){
							case 'o':
								num_must++;
								break;

							case '.':
								//何もしない
								break;

							case '*':
								free_not++;
								break;
							}
							break;
						}
					}

					int work_borrow = borrow;

					if(work_borrow >= num_not){ //★★num_notは優先的に返済に充てる★★

						work_borrow -= num_not;
						num_not = 0;

					}else{ //work_borrow < num_not;

						num_not -= work_borrow;
						work_borrow = 0;
					}


					int num_free = free_match+free_not; //自由マスの数
					int tmp_carry,tmp_borrow,tmp_free_match;

					for(int add = 0; add <= num_free; add++){

						tmp_carry= carry;
						tmp_borrow = work_borrow;
						tmp_free_match = free_match;
						int tmp_add = 0;

						if(tmp_borrow >= tmp_free_match){ //★★tmp_free_matchも返済を優先する★★
							tmp_borrow -= tmp_free_match;
							tmp_free_match = 0;
						}else{
							tmp_free_match -= tmp_borrow;
							tmp_borrow = 0;
						}

						vector<State> S;

						if(add == 0){ //★free_matchは全てその場から動かす★

							if(num_must == 1 && num_not == 1){

								if(tmp_carry >= num_must){

									tmp_carry -= num_must;
									tmp_carry += num_not;

									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow));

								}else{ //tmp_carry < num_must

									tmp_carry = 0;

									//num_notを充てる
									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+1));
								}

							}else{

								if(num_not == 0){

									if(num_must > 0){ //num_not == 0

										if(tmp_carry >= num_must){

											tmp_carry -= num_must;
											tmp_carry += tmp_free_match;

										}else{ //tmp_carry < num_must

											int rest = num_must-tmp_carry; //とりあえずcarryでmustを埋める
											tmp_carry = 0;

											if(tmp_free_match >= rest){

												tmp_add += rest;
												tmp_free_match -= rest;

												//持ち越すか否かの判断
												if(tmp_borrow >= tmp_free_match){

													tmp_borrow -= tmp_free_match;

												}else{//tmp_borrow < tmp_free_match

													tmp_free_match -= tmp_borrow;
													tmp_borrow = 0;
													tmp_carry += tmp_free_match;
												}

											}else{ //tmp_free_match < rest

												tmp_add += tmp_free_match;
												rest -= tmp_free_match;
												tmp_free_match = 0;

												tmp_borrow += rest;
											}
										}

									}else{ //num_must == 0 :1枚もコインを置かない

										int move = tmp_free_match+num_not;

										if(tmp_borrow >= move){

											tmp_borrow -= move; //borrowの返済に充てる

										}else{ //tmp_borrow < move

											move -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry += move;
										}
									}

								}else{ //num_must == 0 && num_not > 0

									int move = tmp_free_match+num_not;

									if(tmp_borrow >= move){

										tmp_borrow -= move; //borrowの返済に充てる

									}else{ //tmp_borrow < move

										move -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += move;
									}
								}
								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
							}

						}else if(add == 1){

							int rest = add;
							if(tmp_free_match >= rest){ //コスト0処理
								tmp_free_match -= rest;
								rest = 0;

							}

							rest += num_must; //置かなければいけない枚数
							int this_got = num_not+tmp_free_match; //今回手に入った枚数

							if(tmp_carry >= rest){

								tmp_carry -= rest;
								if(tmp_borrow >= this_got){

									tmp_borrow -= this_got;
								}else{
									this_got -= tmp_borrow;
									tmp_borrow = 0;
									tmp_carry += this_got;
								}

							}else{ //tmp_carry < rest

								rest -= tmp_carry;
								tmp_carry = 0;

								if(this_got >= rest){

									this_got -= rest;
									tmp_add += rest;
									rest = 0;


									if(tmp_borrow >= this_got){

										tmp_borrow -= this_got;

									}else{ //tmp_borrow < this_got

										this_got -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += this_got;
									}

								}else{ //this_got < rest

									tmp_add += this_got;
									rest -= this_got;
									this_got = 0;
									tmp_borrow += rest;
								}
							}

							S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));

					}else{ //add == 2 (num_not == 0 && num_must == 0)

						if(add <= tmp_free_match){ //add分は全てfree_matchで賄う

							//Do nothing(tmp_free_mathが2枚)
						}else{ //add > tmp_free_match (add-free_match個、どこかから引っ張ってくる)

							int rest = add-tmp_free_match;
							tmp_free_match = 0;

							if(tmp_carry >= rest){

								tmp_carry -= rest;

							}else{ //tmp_carry < rest;

								rest -= tmp_carry;
								tmp_carry = 0;

								tmp_borrow += rest;
							}
						}

						S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
					}

					for(int a = 0; a < S.size(); a++){
						if(S[a].tmp_borrow > num_R[col+1])continue;

						if(S[a].tmp_borrow == 0){

							if(dp[col][CARRY][S[a].tmp_carry] > dp[col-1][loop][i]+S[a].cost){

								dp[col][CARRY][S[a].tmp_carry] = dp[col-1][loop][i]+S[a].cost;
						}

						}else{
							if(dp[col][BORROW][S[a].tmp_borrow] > dp[col-1][loop][i]+S[a].cost){
								dp[col][BORROW][S[a].tmp_borrow] = dp[col-1][loop][i]+S[a].cost;
							}
						}
					}
				}
			}
		}
	}

	printf("%d\n",dp[W][CARRY][0]);

	return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 65952
final_rank: 3

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 4005
#define MAX 4005

enum Which{
	CARRY,
	BORROW,
};


struct Info{
	void set(int arg_carry,int arg_borrow){
		carry = arg_carry;
		borrow = arg_borrow;
	}
	int carry,borrow;
};


struct State{
	State(int arg_tmp_carry,int arg_tmp_borrow,int arg_cost){
		tmp_carry = arg_tmp_carry;
		tmp_borrow = arg_tmp_borrow;
		cost = arg_cost;
	}
	int tmp_carry,tmp_borrow,cost;
};

int W;
int num_L[SIZE],num_R[SIZE];
int must_L[SIZE],free_L[SIZE];
int dp[2005][2][MAX];
char FROM[2][SIZE],TO[2][SIZE];


int main(){

	scanf("%d",&W);

	for(int row = 0; row < 2; row++){
		scanf("%s",FROM[row]);
		for(int col = W-1; col >= 0; col--){
			FROM[row][col+1] = FROM[row][col]; //右に詰める
		}
	}

	for(int row = 0; row < 2; row++){
		scanf("%s",TO[row]);
		for(int col = W-1; col >= 0; col--){
			TO[row][col+1] = TO[row][col]; //右に詰める
		}
	}

	for(int i = 0; i <= W+1; i++){
		num_L[i] = 0;
		num_R[i] = 0;
		must_L[i] = 0;
		free_L[i] = 0;
	}

	//ある列以西にあるコインの数
	num_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(FROM[0][col] == 'o')num_L[col]++;
		if(FROM[1][col] == 'o')num_L[col]++;

		num_L[col] += num_L[col-1];
	}

	//ある列以東にあるコインの数
	num_R[W+1] = 0;
	for(int col = W; col >= 1; col--){
		if(FROM[0][col] == 'o')num_R[col]++;
		if(FROM[1][col] == 'o')num_R[col]++;

		num_R[col] += num_R[col+1];
	}

	//ある列以西にある、必須マスの数
	must_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == 'o')must_L[col]++;
		if(TO[1][col] == 'o')must_L[col]++;

		must_L[col] += must_L[col-1];
	}

	//ある列以西にある、自由マスの数
	free_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == '*')free_L[col]++;
		if(TO[1][col] == '*')free_L[col]++;

		free_L[col] += free_L[col-1];
	}

	for(int col = 0; col <= W+1; col++){
		for(int a = 0; a < 2; a++){
			for(int k = 0; k < MAX; k++){

				dp[col][a][k] = BIG_NUM;
			}
		}
	}

	dp[0][CARRY][0] = 0;


	int carry,borrow;
	int num;

	//★borrowが不適なら遷移しない★
	for(int col = 1; col <= W; col++){

		//printf("col:%d\n",col);

		for(int loop = 0; loop < 2; loop++){

			int start = 0;
			if(loop == 0){ //CARRAY

				borrow = 0;

			}else{ //borrow

				carry = 0;
				start = 1;
			}
			for(int i = start; i < MAX; i++){
					if(dp[col-1][loop][i] == BIG_NUM)continue;

					if(loop == 0){

						carry = i;
					}else{

						borrow = i;
					}

					int A = num_L[col-1]-must_L[col-1]; //拾った数
					if(loop == 0){

						num = A-carry; //置いた数 = 拾った数-carry数
					}else{ //loop == 1

						num = A+borrow; //置いた数 = 拾った数+前借の数
					}

					//例外ケース処理
					if(col <= W-1 && (FROM[0][col+1] == 'o' && FROM[0][col] == '.' && FROM[1][col+1] == '.' && FROM[1][col] == 'o') &&
						TO[0][col+1] != 'o' && TO[0][col] != '.' && TO[1][col+1] != '.' && TO[1][col] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					if(col <= W-1  && (FROM[0][col+1] == '.' && FROM[0][col] == 'o' && FROM[1][col+1] == 'o' && FROM[1][col] == '.') &&
							TO[0][col] != 'o' && TO[0][col+1] != '.' && TO[1][col] != '.' && TO[1][col+1] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					//printf("\nnum:%d cost:%d\n",num,dp[pre][num]);

					//printf("num:%d carry:%d borrow:%d\n",num,carry,borrow);

					int num_must = 0,num_not = 0;
					int free_match = 0,free_not = 0;

					for(int row = 0; row < 2; row++){
						switch(FROM[row][col]){
						case 'o':
							switch(TO[row][col]){
							case 'o':
								//そのまま
								break;

							case '.':
								num_not++;
								break;

							case '*':
								free_match++;
								break;
							}
							break;


						case '.':
							switch(TO[row][col]){
							case 'o':
								num_must++;
								break;

							case '.':
								//何もしない
								break;

							case '*':
								free_not++;
								break;
							}
							break;
						}
					}

					int work_borrow = borrow;

					if(work_borrow >= num_not){ //★★num_notは優先的に返済に充てる★★

						work_borrow -= num_not;
						num_not = 0;

					}else{ //work_borrow < num_not;

						num_not -= work_borrow;
						work_borrow = 0;
					}


					int num_free = free_match+free_not; //自由マスの数
					int tmp_carry,tmp_borrow,tmp_free_match;

					//printf("num_free:%d free_match:%d free_not:%d\n",num_free,free_match,free_not);
					//printf("carry:%d borrow:%d\n",carry,borrow);

					for(int add = 0; add <= num_free; add++){

						tmp_carry= carry;
						tmp_borrow = work_borrow;
						tmp_free_match = free_match;
						int tmp_add = 0;

						if(tmp_borrow >= tmp_free_match){
							tmp_borrow -= tmp_free_match;
							tmp_free_match = 0;
						}else{
							tmp_free_match -= tmp_borrow;
							tmp_borrow = 0;
						}

						vector<State> S;

						if(add == 0){ //★free_matchは全てその場から動かす★

							if(num_must == 1 && num_not == 1){

								if(tmp_carry >= num_must){

									tmp_carry -= num_must;
									tmp_carry += num_not;

									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow));

								}else{ //tmp_carry < num_must

									tmp_carry = 0;

									//★num_notを充てる場合★
									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+1));

									//tmp_borrowでやる場合?

								}

							}else{

								if(num_not == 0){

									if(num_must > 0){ //num_not == 0

										if(tmp_carry >= num_must){

											tmp_carry -= num_must;
											tmp_carry += tmp_free_match;

										}else{ //tmp_carry < num_must

											int rest = num_must-tmp_carry; //とりあえずcarryでmustを埋める
											tmp_carry = 0;

											if(tmp_free_match >= rest){

												tmp_add += rest;
												tmp_free_match -= rest;

												//持ち越すか否かの判断
												if(tmp_borrow >= tmp_free_match){

													tmp_borrow -= tmp_free_match;

												}else{//tmp_borrow < tmp_free_match

													tmp_free_match -= tmp_borrow;
													tmp_borrow = 0;
													tmp_carry += tmp_free_match;
												}

											}else{ //tmp_free_match < rest

												tmp_add += tmp_free_match;
												rest -= tmp_free_match;
												tmp_free_match = 0;

												tmp_borrow += rest;
											}
										}

									}else{ //num_must == 0 :1枚もコインを置かない

										int move = tmp_free_match+num_not;

										if(tmp_borrow >= move){

											tmp_borrow -= move; //borrowの返済に充てる

										}else{ //tmp_borrow < move

											move -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry += move;
										}
									}

								}else{ //num_must == 0 && num_not > 0

									int move = tmp_free_match+num_not;

									if(tmp_borrow >= move){

										tmp_borrow -= move; //borrowの返済に充てる

									}else{ //tmp_borrow < move

										move -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += move;
									}
								}
								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
							}

						}else if(add == 1){

							int rest = add;
							if(tmp_free_match >= rest){ //コスト0処理
								tmp_free_match -= rest;
								rest = 0;

							}

							rest += num_must; //置かなければいけない枚数
							int this_got = num_not+tmp_free_match; //今回手に入った枚数

							if(tmp_carry >= rest){

								tmp_carry -= rest;
								if(tmp_borrow >= this_got){

									tmp_borrow -= this_got;
								}else{
									this_got -= tmp_borrow;
									tmp_borrow = 0;
									tmp_carry += this_got;
								}

							}else{ //tmp_carry < rest

								rest -= tmp_carry;
								tmp_carry = 0;

								if(this_got >= rest){

									this_got -= rest;
									tmp_add += rest;
									rest = 0;


									if(tmp_borrow >= this_got){

										tmp_borrow -= this_got;

									}else{ //tmp_borrow < this_got

										this_got -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += this_got;
									}

								}else{ //this_got < rest

									tmp_add += this_got;
									rest -= this_got;
									this_got = 0;
									tmp_borrow += rest;
								}
							}

							S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));

					}else{ //add == 2 (num_not == 0 && num_must == 0)

						if(add <= tmp_free_match){ //add分は全てfree_matchで賄う

							//Do nothing(tmp_free_mathが2枚)
						}else{ //add > tmp_free_match (add-free_match個、どこかから引っ張ってくる)

							int rest = add-tmp_free_match;
							tmp_free_match = 0;

							if(tmp_carry >= rest){

								tmp_carry -= rest;

							}else{ //tmp_carry < rest;

								rest -= tmp_carry;
								tmp_carry = 0;

								tmp_borrow += rest;
							}
						}

						S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
					}

					for(int a = 0; a < S.size(); a++){
						if(S[a].tmp_borrow > num_R[col+1])continue;

						if(S[a].tmp_borrow == 0){

							if(dp[col][CARRY][S[a].tmp_carry] > dp[col-1][loop][i]+S[a].cost){
							//printf("CARRY:%dを%dで更新\n",S[a].tmp_carry,dp[pre][loop][i]+S[a].cost);

								dp[col][CARRY][S[a].tmp_carry] = dp[col-1][loop][i]+S[a].cost;
						}

						}else{
							if(dp[col][BORROW][S[a].tmp_borrow] > dp[col-1][loop][i]+S[a].cost){
								//printf("BORROW:%dを%dで更新\n",S[a].tmp_borrow,dp[pre][loop][i]+S[a].cost);
								dp[col][BORROW][S[a].tmp_borrow] = dp[col-1][loop][i]+S[a].cost;
							}
						}
					}
				}
			}
		}
	}

	printf("%d\n",dp[W][CARRY][0]);

	return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 65952
final_rank: 3

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 4005
#define MAX 4005

enum Which{
	CARRY,
	BORROW,
};


struct Info{
	void set(int arg_carry,int arg_borrow){
		carry = arg_carry;
		borrow = arg_borrow;
	}
	int carry,borrow;
};


struct State{
	State(int arg_tmp_carry,int arg_tmp_borrow,int arg_cost){
		tmp_carry = arg_tmp_carry;
		tmp_borrow = arg_tmp_borrow;
		cost = arg_cost;
	}
	int tmp_carry,tmp_borrow,cost;
};

int W;
int num_L[SIZE],num_R[SIZE];
int must_L[SIZE],free_L[SIZE];
int dp[2005][2][MAX];
char FROM[2][SIZE],TO[2][SIZE];


int main(){

	scanf("%d",&W);

	for(int row = 0; row < 2; row++){
		scanf("%s",FROM[row]);
		for(int col = W-1; col >= 0; col--){
			FROM[row][col+1] = FROM[row][col]; //右に詰める
		}
	}

	for(int row = 0; row < 2; row++){
		scanf("%s",TO[row]);
		for(int col = W-1; col >= 0; col--){
			TO[row][col+1] = TO[row][col]; //右に詰める
		}
	}

	for(int i = 0; i <= W+1; i++){
		num_L[i] = 0;
		num_R[i] = 0;
		must_L[i] = 0;
		free_L[i] = 0;
	}

	//ある列以西にあるコインの数
	num_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(FROM[0][col] == 'o')num_L[col]++;
		if(FROM[1][col] == 'o')num_L[col]++;

		num_L[col] += num_L[col-1];
	}

	//ある列以東にあるコインの数
	num_R[W+1] = 0;
	for(int col = W; col >= 1; col--){
		if(FROM[0][col] == 'o')num_R[col]++;
		if(FROM[1][col] == 'o')num_R[col]++;

		num_R[col] += num_R[col+1];
	}

	//ある列以西にある、必須マスの数
	must_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == 'o')must_L[col]++;
		if(TO[1][col] == 'o')must_L[col]++;

		must_L[col] += must_L[col-1];
	}

	//ある列以西にある、自由マスの数
	free_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == '*')free_L[col]++;
		if(TO[1][col] == '*')free_L[col]++;

		free_L[col] += free_L[col-1];
	}

	for(int col = 0; col <= W+1; col++){
		for(int a = 0; a < 2; a++){
			for(int k = 0; k < MAX; k++){

				dp[col][a][k] = BIG_NUM;
			}
		}
	}

	dp[0][CARRY][0] = 0;


	int carry,borrow;
	int num;

	//★borrowが不適なら遷移しない★
	for(int col = 1; col <= W; col++){

		//printf("col:%d\n",col);

		for(int loop = 0; loop < 2; loop++){

			int start = 0;
			if(loop == 0){ //CARRAY

				borrow = 0;

			}else{ //borrow

				carry = 0;
				start = 1;
			}
			for(int i = start; i < MAX; i++){
				if(dp[col-1][loop][i] == BIG_NUM)continue;

				if(loop == 0){

					carry = i;
				}else{

					borrow = i;
				}

				int A = num_L[col-1]-must_L[col-1]; //拾った数
				if(loop == 0){

					num = A-carry; //置いた数 = 拾った数-carry数
				}else{ //loop == 1

					num = A+borrow; //置いた数 = 拾った数+前借の数
				}

				//例外ケース処理
				if(col <= W-1 && (FROM[0][col+1] == 'o' && FROM[0][col] == '.' && FROM[1][col+1] == '.' && FROM[1][col] == 'o') &&
						TO[0][col+1] != 'o' && TO[0][col] != '.' && TO[1][col+1] != '.' && TO[1][col] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					if(col <= W-1  && (FROM[0][col+1] == '.' && FROM[0][col] == 'o' && FROM[1][col+1] == 'o' && FROM[1][col] == '.') &&
							TO[0][col] != 'o' && TO[0][col+1] != '.' && TO[1][col] != '.' && TO[1][col+1] != 'o'){

						if(borrow == 0){

							if(dp[col+1][CARRY][carry] > dp[col-1][CARRY][carry]+2*(carry+borrow)+1){

								dp[col+1][CARRY][carry] = dp[col-1][CARRY][carry]+2*(carry+borrow)+1;
							}

						}else{

							if(dp[col+1][BORROW][borrow] > dp[col-1][BORROW][borrow]+2*(carry+borrow)+1){

								dp[col+1][BORROW][borrow] = dp[col-1][BORROW][borrow]+2*(carry+borrow)+1;
							}
						}
					}

					//printf("\nnum:%d cost:%d\n",num,dp[pre][num]);

					//printf("num:%d carry:%d borrow:%d\n",num,carry,borrow);

					int num_must = 0,num_not = 0;
					int free_match = 0,free_not = 0;

					for(int row = 0; row < 2; row++){
						switch(FROM[row][col]){
						case 'o':
							switch(TO[row][col]){
							case 'o':
								//そのまま
								break;

							case '.':
								num_not++;
								break;

							case '*':
								free_match++;
								break;
							}
							break;


						case '.':
							switch(TO[row][col]){
							case 'o':
								num_must++;
								break;

							case '.':
								//何もしない
								break;

							case '*':
								free_not++;
								break;
							}
							break;
						}
					}

					int work_borrow = borrow;

					if(work_borrow >= num_not){ //★★num_notは優先的に返済に充てる★★

						work_borrow -= num_not;
						num_not = 0;

					}else{ //work_borrow < num_not;

						num_not -= work_borrow;
						work_borrow = 0;
					}


					int num_free = free_match+free_not; //自由マスの数
					int tmp_carry,tmp_borrow,tmp_free_match;

					//printf("num_free:%d free_match:%d free_not:%d\n",num_free,free_match,free_not);
					//printf("carry:%d borrow:%d\n",carry,borrow);

					for(int add = 0; add <= num_free; add++){

						tmp_carry= carry;
						tmp_borrow = work_borrow;
						tmp_free_match = free_match;
						int tmp_add = 0;

						vector<State> S;

						if(add == 0){ //★free_matchは全てその場から動かす★

							if(num_must == 1 && num_not == 1){

								if(tmp_carry >= num_must){

									tmp_carry -= num_must;
									tmp_carry += num_not;

									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow));

								}else{ //tmp_carry < num_must

									tmp_carry = 0;

									//★num_notを充てる場合★
									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+1));

									//tmp_borrowでやる場合?

								}

							}else{

								if(num_not == 0){

									if(num_must > 0){ //num_not == 0

										if(tmp_carry >= num_must){

											tmp_carry -= num_must;
											tmp_carry += tmp_free_match;

										}else{ //tmp_carry < num_must

											int rest = num_must-tmp_carry; //とりあえずcarryでmustを埋める
											tmp_carry = 0;

											if(tmp_free_match >= rest){

												tmp_add += rest;
												tmp_free_match -= rest;

												//持ち越すか否かの判断
												if(tmp_borrow >= tmp_free_match){

													tmp_borrow -= tmp_free_match;

												}else{//tmp_borrow < tmp_free_match

													tmp_free_match -= tmp_borrow;
													tmp_borrow = 0;
													tmp_carry += tmp_free_match;
												}

											}else{ //tmp_free_match < rest

												tmp_add += tmp_free_match;
												rest -= tmp_free_match;
												tmp_free_match = 0;

												tmp_borrow += rest;
											}
										}

									}else{ //num_must == 0 :1枚もコインを置かない

										int move = tmp_free_match+num_not;

										if(tmp_borrow >= move){

											tmp_borrow -= move; //borrowの返済に充てる

										}else{ //tmp_borrow < move

											move -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry += move;
										}
									}

								}else{ //num_must == 0 && num_not > 0

									int move = tmp_free_match+num_not;

									if(tmp_borrow >= move){

										tmp_borrow -= move; //borrowの返済に充てる

									}else{ //tmp_borrow < move

										move -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += move;
									}
								}
								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
							}

						}else if(add == 1){

							int rest = add;
							if(tmp_free_match >= rest){ //コスト0処理
								tmp_free_match -= rest;
								rest = 0;

							}

							rest += num_must; //置かなければいけない枚数
							int this_got = num_not+tmp_free_match; //今回手に入った枚数

							if(tmp_carry >= rest){

								tmp_carry -= rest;
								if(tmp_borrow >= this_got){

									tmp_borrow -= this_got;
								}else{
									this_got -= tmp_borrow;
									tmp_borrow = 0;
									tmp_carry += this_got;
								}

							}else{ //tmp_carry < rest

								rest -= tmp_carry;
								tmp_carry = 0;

								if(this_got >= rest){

									this_got -= rest;
									tmp_add += rest;
									rest = 0;


									if(tmp_borrow >= this_got){

										tmp_borrow -= this_got;

									}else{ //tmp_borrow < this_got

										this_got -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += this_got;
									}

								}else{ //this_got < rest

									tmp_add += this_got;
									rest -= this_got;
									this_got = 0;
									tmp_borrow += rest;
								}
							}

							S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));

					}else{ //add == 2 (num_not == 0 && num_must == 0)

						if(add <= tmp_free_match){ //add分は全てfree_matchで賄う

							//Do nothing(tmp_free_mathが2枚)
						}else{ //add > tmp_free_match (add-free_match個、どこかから引っ張ってくる)

							int rest = add-tmp_free_match;
							tmp_free_match = 0;

							if(tmp_carry >= rest){

								tmp_carry -= rest;

							}else{ //tmp_carry < rest;

								rest -= tmp_carry;
								tmp_carry = 0;

								tmp_borrow += rest;
							}
						}

						S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
					}

					for(int a = 0; a < S.size(); a++){
						if(S[a].tmp_borrow > num_R[col+1])continue;

						if(S[a].tmp_borrow == 0){

							if(dp[col][CARRY][S[a].tmp_carry] > dp[col-1][loop][i]+S[a].cost){
							//printf("CARRY:%dを%dで更新\n",S[a].tmp_carry,dp[pre][loop][i]+S[a].cost);

								dp[col][CARRY][S[a].tmp_carry] = dp[col-1][loop][i]+S[a].cost;
						}

						}else{
							if(dp[col][BORROW][S[a].tmp_borrow] > dp[col-1][loop][i]+S[a].cost){
								//printf("BORROW:%dを%dで更新\n",S[a].tmp_borrow,dp[pre][loop][i]+S[a].cost);
								dp[col][BORROW][S[a].tmp_borrow] = dp[col-1][loop][i]+S[a].cost;
							}
						}
					}
				}
			}
		}
	}

	printf("%d\n",dp[W][CARRY][0]);

	return 0;
}
accuracy: 0.8
time_ms: 240
memory_kb: 65948
final_rank: 5

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 4005
#define MAX 4005

enum Which{
	CARRY,
	BORROW,
};

enum Type{
	pre_pre,
	pre,
};

struct Info{
	void set(int arg_carry,int arg_borrow){
		carry = arg_carry;
		borrow = arg_borrow;
	}
	int carry,borrow;
};

struct Data{

	int work_carry,work_borrow;
};

struct State{
	State(int arg_tmp_carry,int arg_tmp_borrow,int arg_cost){
		tmp_carry = arg_tmp_carry;
		tmp_borrow = arg_tmp_borrow;
		cost = arg_cost;
	}
	int tmp_carry,tmp_borrow,cost;
};

int W;
int num_L[SIZE],num_R[SIZE];
int must_L[SIZE],free_L[SIZE];
int dp[2][2][MAX],work[2][MAX];
char FROM[2][SIZE],TO[2][SIZE];
vector<Data> DATA[2][MAX],work_DATA[MAX];


int main(){

	scanf("%d",&W);

	for(int row = 0; row < 2; row++){
		scanf("%s",FROM[row]);
		for(int col = W-1; col >= 0; col--){
			FROM[row][col+1] = FROM[row][col]; //右に詰める
		}
	}

	for(int row = 0; row < 2; row++){
		scanf("%s",TO[row]);
		for(int col = W-1; col >= 0; col--){
			TO[row][col+1] = TO[row][col]; //右に詰める
		}
	}

	for(int i = 0; i <= W+1; i++){
		num_L[i] = 0;
		num_R[i] = 0;
		must_L[i] = 0;
		free_L[i] = 0;
	}

	//ある列以西にあるコインの数
	num_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(FROM[0][col] == 'o')num_L[col]++;
		if(FROM[1][col] == 'o')num_L[col]++;

		num_L[col] += num_L[col-1];
	}

	//ある列以東にあるコインの数
	num_R[W+1] = 0;
	for(int col = W; col >= 1; col--){
		if(FROM[0][col] == 'o')num_R[col]++;
		if(FROM[1][col] == 'o')num_R[col]++;

		num_R[col] += num_R[col+1];
	}

	//ある列以西にある、必須マスの数
	must_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == 'o')must_L[col]++;
		if(TO[1][col] == 'o')must_L[col]++;

		must_L[col] += must_L[col-1];
	}

	//ある列以西にある、自由マスの数
	free_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == '*')free_L[col]++;
		if(TO[1][col] == '*')free_L[col]++;

		free_L[col] += free_L[col-1];
	}

	for(int i = 0; i < 2; i++){
		for(int k = 0; k < 2; k++){
			for(int a = 0; a < MAX; a++){

				dp[i][k][a] = BIG_NUM;
			}
		}
	}

	dp[pre][CARRY][0] = 0;

	Data first_data;
	first_data.work_carry = 0;
	first_data.work_borrow = 0;

	DATA[pre][0].push_back(first_data);

	int carry,borrow;
	int num;

	//★borrowが不適なら遷移しない★
	for(int col = 1; col <= W; col++){

		for(int loop = 0; loop < 2; loop++){
			for(int i = 0; i < MAX; i++){

				work[loop][i] = BIG_NUM;
			}
		}

		for(int i = 0; i < MAX; i++){

			work_DATA[i].clear();
		}

		//printf("col:%d\n",col);

		for(int loop = 0; loop < 2; loop++){

			int start = 0;
			if(loop == 0){ //CARRAY

				borrow = 0;

			}else{ //borrow

				carry = 0;
				start = 1;
			}
			for(int i = start; i < MAX; i++){
				if(dp[pre][loop][i] == BIG_NUM)continue;

				if(loop == 0){

					carry = i;
				}else{

					borrow = i;
				}

				int A = num_L[col-1]-must_L[col-1]; //拾った数
				if(loop == 0){

					num = A-carry; //置いた数 = 拾った数-carry数
				}else{ //loop == 1

					num = A+borrow; //置いた数 = 拾った数+前借の数
				}

				Data tmp_data;
				tmp_data.work_carry = carry;
				tmp_data.work_borrow = borrow;

				work_DATA[num].push_back(tmp_data); //個数,carry,borrowを記録

				//例外ケース処理
				if(col >=2 && (FROM[0][col] == 'o' && FROM[0][col-1] == '.' && FROM[1][col] == '.' && FROM[1][col-1] == 'o') &&
						TO[0][col] != 'o' && TO[0][col-1] != '.' && TO[1][col] != '.' && TO[1][col-1] != 'o'){

						int pre_a = num;
						if(TO[0][col-1] == '*')pre_a--;
						if(TO[1][col-1] == '*')pre_a--;

						for(int a = max(0,pre_a); a <= num; a++){
							for(int b = 0; b < DATA[pre_pre][a].size(); b++){

								int tmp_carry = DATA[pre_pre][a][b].work_carry;
								int tmp_borrow = DATA[pre_pre][a][b].work_borrow;

								if(tmp_borrow > num_R[col+1])continue;

								if(tmp_borrow == 0){

									if(work[CARRY][tmp_carry] > dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1){

										work[CARRY][tmp_carry] = dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1;
									}
								}else{

									if(work[BORROW][tmp_borrow] > dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1){

										work[BORROW][tmp_borrow] = dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1;
									}
								}
							}
						}
					}

					if(col >=2 && (FROM[0][col] == '.' && FROM[0][col-1] == 'o' && FROM[1][col] == 'o' && FROM[1][col-1] == '.') &&
							TO[0][col-1] != 'o' && TO[0][col] != '.' && TO[1][col-1] != '.' && TO[1][col] != 'o'){

						int pre_a = num;
						if(TO[0][col-1] == '*')pre_a--;
						if(TO[1][col-1] == '*')pre_a--;

						for(int a = max(0,pre_a); a <= num; a++){
							for(int b = 0; b < DATA[pre_pre][a].size(); b++){

								int tmp_carry = DATA[pre_pre][a][b].work_carry;
								int tmp_borrow = DATA[pre_pre][a][b].work_borrow;

								if(tmp_borrow > num_R[col+1])continue;

								if(tmp_borrow == 0){

									if(work[CARRY][tmp_carry] > dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1){

										work[CARRY][tmp_carry] = dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1;
									}
								}else{

									if(work[BORROW][tmp_borrow] > dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1){

										work[BORROW][tmp_borrow] = dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1;
									}
								}
							}
						}
					}

					//printf("\nnum:%d cost:%d\n",num,dp[pre][num]);

					//printf("num:%d carry:%d borrow:%d\n",num,carry,borrow);

					int num_must = 0,num_not = 0;
					int free_match = 0,free_not = 0;

					for(int row = 0; row < 2; row++){
						switch(FROM[row][col]){
						case 'o':
							switch(TO[row][col]){
							case 'o':
								//そのまま
								break;

							case '.':
								num_not++;
								break;

							case '*':
								free_match++;
								break;
							}
							break;


						case '.':
							switch(TO[row][col]){
							case 'o':
								num_must++;
								break;

							case '.':
								//何もしない
								break;

							case '*':
								free_not++;
								break;
							}
							break;
						}
					}

					int work_borrow = borrow;

					if(work_borrow >= num_not){ //★★num_notは優先的に返済に充てる★★

						work_borrow -= num_not;
						num_not = 0;

					}else{ //work_borrow < num_not;

						num_not -= work_borrow;
						work_borrow = 0;
					}


					int num_free = free_match+free_not; //自由マスの数
					int tmp_carry,tmp_borrow,tmp_free_match;

					//printf("num_free:%d free_match:%d free_not:%d\n",num_free,free_match,free_not);
					//printf("carry:%d borrow:%d\n",carry,borrow);

					for(int add = 0; add <= num_free; add++){

						tmp_carry= carry;
						tmp_borrow = work_borrow;
						tmp_free_match = free_match;
						int tmp_add = 0;

						vector<State> S;

						if(add == 0){ //★free_matchは全てその場から動かす★

							if(num_must == 1 && num_not == 1){

								if(tmp_carry >= num_must){

									tmp_carry -= num_must;
									tmp_carry += num_not;

									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow));

								}else{ //tmp_carry < num_must

									int rest = num_must-tmp_carry;
									tmp_carry = 0;

									//★num_notを充てる場合★
									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+1));

									//tmp_borrowでやる場合?
								}

							}else{

								if(num_not == 0){

									if(num_must > 0){ //num_not == 0

										if(tmp_carry >= num_must){

											tmp_carry -= num_must;
											tmp_carry += tmp_free_match;

										}else{ //tmp_carry < num_must

											int rest = num_must-tmp_carry; //とりあえずcarryでmustを埋める
											tmp_carry = 0;

											if(tmp_free_match >= rest){

												tmp_add += rest;
												tmp_free_match -= rest;

												//持ち越すか否かの判断
												if(tmp_borrow >= tmp_free_match){

													tmp_borrow -= tmp_free_match;

												}else{//tmp_borrow < tmp_free_match

													tmp_free_match -= tmp_borrow;
													tmp_borrow = 0;
													tmp_carry += tmp_free_match;
												}

											}else{ //tmp_free_match < rest

												tmp_add += tmp_free_match;
												rest -= tmp_free_match;
												tmp_free_match = 0;

												tmp_borrow += rest;
											}
										}

									}else{ //num_must == 0 :1枚もコインを置かない

										int move = tmp_free_match+num_not;

										if(tmp_borrow >= move){

											tmp_borrow -= move; //borrowの返済に充てる

										}else{ //tmp_borrow < move

											move -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry += move;
										}
									}

								}else{ //num_must == 0 && num_not > 0

									int move = tmp_free_match+num_not;

									if(tmp_borrow >= move){

										tmp_borrow -= move; //borrowの返済に充てる

									}else{ //tmp_borrow < move

										move -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += move;
									}
								}
								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
							}

						}else if(add == 1){

							int rest = add;
								if(tmp_free_match >= rest){ //コスト0処理
									tmp_free_match -= rest;
									rest = 0;

								}

								rest += num_must; //置かなければいけない枚数
								int this_got = num_not+tmp_free_match; //今回手に入った枚数

								if(tmp_carry >= rest){

									tmp_carry -= rest;
									if(tmp_borrow >= this_got){

										tmp_borrow -= this_got;
									}else{
										this_got -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += this_got;
									}

								}else{ //tmp_carry < rest

									rest -= tmp_carry;
									tmp_carry = 0;

									if(this_got >= rest){

										this_got -= rest;
										tmp_add += rest;
										rest = 0;


										if(tmp_borrow >= this_got){

											tmp_borrow -= this_got;

										}else{ //tmp_borrow < this_got

											this_got -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry = this_got;
										}

									}else{ //this_got < rest

										tmp_add += this_got;
										rest -= this_got;
										this_got = 0;
										tmp_borrow += rest;
									}
								}

								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));

						}else{ //add == 2 (num_not == 0 && num_must == 0)

							if(add <= tmp_free_match){ //add分は全てfree_matchで賄う

								//Do nothing(tmp_free_mathが2枚)
							}else{ //add > tmp_free_match (add-free_match個、どこかから引っ張ってくる)

								int rest = add-tmp_free_match;
								tmp_free_match = 0;

								if(tmp_carry >= rest){

									tmp_carry -= rest;

								}else{ //tmp_carry < rest;

									rest -= tmp_carry;
									tmp_carry = 0;

									tmp_borrow += rest;
								}
							}

							S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
						}

						for(int a = 0; a < S.size(); a++){
							if(S[a].tmp_borrow > num_R[col+1])continue;

							if(S[a].tmp_borrow == 0){

								if(work[CARRY][S[a].tmp_carry] > dp[pre][loop][i]+S[a].cost){
								//printf("CARRY:%dを%dで更新\n",S[a].tmp_carry,dp[pre][loop][i]+S[a].cost);

								work[CARRY][S[a].tmp_carry] = dp[pre][loop][i]+S[a].cost;
							}

							}else{
								if(work[BORROW][S[a].tmp_borrow] > dp[pre][loop][i]+S[a].cost){
									//printf("BORROW:%dを%dで更新\n",S[a].tmp_borrow,dp[pre][loop][i]+S[a].cost);
									work[BORROW][S[a].tmp_borrow] = dp[pre][loop][i]+S[a].cost;
								}
							}
						}
					}

			}

		}
		for(int num = 0; num < MAX; num++){
			dp[pre_pre][CARRY][num] = dp[pre][CARRY][num];
			dp[pre_pre][BORROW][num] = dp[pre][BORROW][num];

			dp[pre][CARRY][num] = work[CARRY][num];
			dp[pre][BORROW][num] = work[BORROW][num];


			DATA[pre_pre][num] = DATA[pre][num];
			DATA[pre][num] = work_DATA[num];
		}
	}

	printf("%d\n",dp[pre][CARRY][0]);

	return 0;
}
accuracy: 0.7
time_ms: 300
memory_kb: 3792
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 2005
#define MAX 2005

enum Which{
	CARRY,
	BORROW,
};

enum Type{
	pre_pre,
	pre,
};

struct Info{
	void set(int arg_carry,int arg_borrow){
		carry = arg_carry;
		borrow = arg_borrow;
	}
	int carry,borrow;
};

struct Data{

	int work_carry,work_borrow;
};

struct State{
	State(int arg_tmp_carry,int arg_tmp_borrow,int arg_cost){
		tmp_carry = arg_tmp_carry;
		tmp_borrow = arg_tmp_borrow;
		cost = arg_cost;
	}
	int tmp_carry,tmp_borrow,cost;
};

int W;
int num_L[SIZE],num_R[SIZE];
int must_L[SIZE],free_L[SIZE];
int dp[2][2][MAX],work[2][MAX];
char FROM[2][SIZE],TO[2][SIZE];
vector<Data> DATA[2][MAX],work_DATA[MAX];


int main(){

	scanf("%d",&W);

	for(int row = 0; row < 2; row++){
		scanf("%s",FROM[row]);
		for(int col = W-1; col >= 0; col--){
			FROM[row][col+1] = FROM[row][col]; //右に詰める
		}
	}

	for(int row = 0; row < 2; row++){
		scanf("%s",TO[row]);
		for(int col = W-1; col >= 0; col--){
			TO[row][col+1] = TO[row][col]; //右に詰める
		}
	}

	for(int i = 0; i <= W+1; i++){
		num_L[i] = 0;
		num_R[i] = 0;
		must_L[i] = 0;
		free_L[i] = 0;
	}

	//ある列以西にあるコインの数
	num_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(FROM[0][col] == 'o')num_L[col]++;
		if(FROM[1][col] == 'o')num_L[col]++;

		num_L[col] += num_L[col-1];
	}

	//ある列以東にあるコインの数
	num_R[W+1] = 0;
	for(int col = W; col >= 1; col--){
		if(FROM[0][col] == 'o')num_R[col]++;
		if(FROM[1][col] == 'o')num_R[col]++;

		num_R[col] += num_R[col+1];
	}

	//ある列以西にある、必須マスの数
	must_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == 'o')must_L[col]++;
		if(TO[1][col] == 'o')must_L[col]++;

		must_L[col] += must_L[col-1];
	}

	//ある列以西にある、自由マスの数
	free_L[0] = 0;
	for(int col = 1; col <= W; col++){
		if(TO[0][col] == '*')free_L[col]++;
		if(TO[1][col] == '*')free_L[col]++;

		free_L[col] += free_L[col-1];
	}

	for(int i = 0; i < 2; i++){
		for(int k = 0; k < 2; k++){
			for(int a = 0; a < MAX; a++){

				dp[i][k][a] = BIG_NUM;
			}
		}
	}

	dp[pre][CARRY][0] = 0;

	Data first_data;
	first_data.work_carry = 0;
	first_data.work_borrow = 0;

	DATA[pre][0].push_back(first_data);

	int carry,borrow;
	int num;

	//★borrowが不適なら遷移しない★
	for(int col = 1; col <= W; col++){

		for(int loop = 0; loop < 2; loop++){
			for(int i = 0; i < MAX; i++){

				work[loop][i] = BIG_NUM;
			}
		}

		for(int i = 0; i < MAX; i++){

			work_DATA[i].clear();
		}

		//printf("col:%d\n",col);

		for(int loop = 0; loop < 2; loop++){

			int start = 0;
			if(loop == 0){ //CARRAY

				borrow = 0;

			}else{ //borrow

				carry = 0;
				start = 1;
			}
			for(int i = start; i < MAX; i++){
				if(dp[pre][loop][i] == BIG_NUM)continue;

				if(loop == 0){

					carry = i;
				}else{

					borrow = i;
				}

				int A = num_L[col-1]-must_L[col-1]; //拾った数
				if(loop == 0){

					num = A-carry; //置いた数 = 拾った数-carry数
				}else{ //loop == 1

					num = A+borrow; //置いた数 = 拾った数+前借の数
				}

				Data tmp_data;
				tmp_data.work_carry = carry;
				tmp_data.work_borrow = borrow;

				work_DATA[num].push_back(tmp_data); //個数,carry,borrowを記録

				//例外ケース処理
				if(col >=2 && (FROM[0][col] == 'o' && FROM[0][col-1] == '.' && FROM[1][col] == '.' && FROM[1][col-1] == 'o') &&
						TO[0][col] != 'o' && TO[0][col-1] != '.' && TO[1][col] != '.' && TO[1][col-1] != 'o'){

						int pre_a = num;
						if(TO[0][col-1] == '*')pre_a--;
						if(TO[1][col-1] == '*')pre_a--;

						for(int a = max(0,pre_a); a <= num; a++){
							for(int b = 0; b < DATA[pre_pre][a].size(); b++){

								int tmp_carry = DATA[pre_pre][a][b].work_carry;
								int tmp_borrow = DATA[pre_pre][a][b].work_borrow;

								if(tmp_borrow > num_R[col+1])continue;

								if(tmp_borrow == 0){

									if(work[CARRY][tmp_carry] > dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1){

										work[CARRY][tmp_carry] = dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1;
									}
								}else{

									if(work[BORROW][tmp_borrow] > dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1){

										work[BORROW][tmp_borrow] = dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1;
									}
								}
							}
						}
					}

					if(col >=2 && (FROM[0][col] == '.' && FROM[0][col-1] == 'o' && FROM[1][col] == 'o' && FROM[1][col-1] == '.') &&
							TO[0][col-1] != 'o' && TO[0][col] != '.' && TO[1][col-1] != '.' && TO[1][col] != 'o'){

						int pre_a = num;
						if(TO[0][col-1] == '*')pre_a--;
						if(TO[1][col-1] == '*')pre_a--;

						for(int a = max(0,pre_a); a <= num; a++){
							for(int b = 0; b < DATA[pre_pre][a].size(); b++){

								int tmp_carry = DATA[pre_pre][a][b].work_carry;
								int tmp_borrow = DATA[pre_pre][a][b].work_borrow;

								if(tmp_borrow > num_R[col+1])continue;

								if(tmp_borrow == 0){

									if(work[CARRY][tmp_carry] > dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1){

										work[CARRY][tmp_carry] = dp[pre_pre][CARRY][tmp_carry]+2*(tmp_carry+tmp_borrow)+1;
									}
								}else{

									if(work[BORROW][tmp_borrow] > dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1){

										work[BORROW][tmp_borrow] = dp[pre_pre][BORROW][tmp_borrow]+2*(tmp_carry+tmp_borrow)+1;
									}
								}
							}
						}
					}

					//printf("\nnum:%d cost:%d\n",num,dp[pre][num]);

					//printf("num:%d carry:%d borrow:%d\n",num,carry,borrow);

					int num_must = 0,num_not = 0;
					int free_match = 0,free_not = 0;

					for(int row = 0; row < 2; row++){
						switch(FROM[row][col]){
						case 'o':
							switch(TO[row][col]){
							case 'o':
								//そのまま
								break;

							case '.':
								num_not++;
								break;

							case '*':
								free_match++;
								break;
							}
							break;


						case '.':
							switch(TO[row][col]){
							case 'o':
								num_must++;
								break;

							case '.':
								//何もしない
								break;

							case '*':
								free_not++;
								break;
							}
							break;
						}
					}

					int work_borrow = borrow;

					if(work_borrow >= num_not){ //★★num_notは優先的に返済に充てる★★

						work_borrow -= num_not;
						num_not = 0;

					}else{ //work_borrow < num_not;

						num_not -= work_borrow;
						work_borrow = 0;
					}


					int num_free = free_match+free_not; //自由マスの数
					int tmp_carry,tmp_borrow,tmp_free_match;

					//printf("num_free:%d free_match:%d free_not:%d\n",num_free,free_match,free_not);
					//printf("carry:%d borrow:%d\n",carry,borrow);

					for(int add = 0; add <= num_free; add++){

						tmp_carry= carry;
						tmp_borrow = work_borrow;
						tmp_free_match = free_match;
						int tmp_add = 0;

						vector<State> S;

						if(add == 0){ //★free_matchは全てその場から動かす★

							if(num_must == 1 && num_not == 1){

								if(tmp_carry >= num_must){

									tmp_carry -= num_must;
									tmp_carry += num_not;

									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow));

								}else{ //tmp_carry < num_must

									int rest = num_must-tmp_carry;
									tmp_carry = 0;

									//★num_notを充てる場合★
									S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+1));

									//tmp_borrowでやる場合?
								}

							}else{

								if(num_not == 0){

									if(num_must > 0){ //num_not == 0

										if(tmp_carry >= num_must){

											tmp_carry -= num_must;
											tmp_carry += tmp_free_match;

										}else{ //tmp_carry < num_must

											int rest = num_must-tmp_carry; //とりあえずcarryでmustを埋める
											tmp_carry = 0;

											if(tmp_free_match >= rest){

												tmp_add += rest;
												tmp_free_match -= rest;

												//持ち越すか否かの判断
												if(tmp_borrow >= tmp_free_match){

													tmp_borrow -= tmp_free_match;

												}else{//tmp_borrow < tmp_free_match

													tmp_free_match -= tmp_borrow;
													tmp_borrow = 0;
													tmp_carry += tmp_free_match;
												}

											}else{ //tmp_free_match < rest

												tmp_add += tmp_free_match;
												rest -= tmp_free_match;
												tmp_free_match = 0;

												tmp_borrow += rest;
											}
										}

									}else{ //num_must == 0 :1枚もコインを置かない

										int move = tmp_free_match+num_not;

										if(tmp_borrow >= move){

											tmp_borrow -= move; //borrowの返済に充てる

										}else{ //tmp_borrow < move

											move -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry += move;
										}
									}

								}else{ //num_must == 0 && num_not > 0

									int move = tmp_free_match+num_not;

									if(tmp_borrow >= move){

										tmp_borrow -= move; //borrowの返済に充てる

									}else{ //tmp_borrow < move

										move -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += move;
									}
								}
								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
							}

						}else if(add == 1){

							int rest = add;
								if(tmp_free_match >= rest){ //コスト0処理
									tmp_free_match -= rest;
									rest = 0;

								}

								rest += num_must; //置かなければいけない枚数
								int this_got = num_not+tmp_free_match; //今回手に入った枚数

								if(tmp_carry >= rest){

									tmp_carry -= rest;
									if(tmp_borrow >= this_got){

										tmp_borrow -= this_got;
									}else{
										this_got -= tmp_borrow;
										tmp_borrow = 0;
										tmp_carry += this_got;
									}

								}else{ //tmp_carry < rest

									rest -= tmp_carry;
									tmp_carry = 0;

									if(this_got >= rest){

										this_got -= rest;
										tmp_add += rest;
										rest = 0;


										if(tmp_borrow >= this_got){

											tmp_borrow -= this_got;

										}else{ //tmp_borrow < this_got

											this_got -= tmp_borrow;
											tmp_borrow = 0;
											tmp_carry = this_got;
										}

									}else{ //this_got < rest

										tmp_add += this_got;
										rest -= this_got;
										this_got = 0;
										tmp_borrow += rest;
									}
								}

								S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));

						}else{ //add == 2 (num_not == 0 && num_must == 0)

							if(add <= tmp_free_match){ //add分は全てfree_matchで賄う

								//Do nothing(tmp_free_mathが2枚)
							}else{ //add > tmp_free_match (add-free_match個、どこかから引っ張ってくる)

								int rest = add-tmp_free_match;
								tmp_free_match = 0;

								if(tmp_carry >= rest){

									tmp_carry -= rest;

								}else{ //tmp_carry < rest;

									rest -= tmp_carry;
									tmp_carry = 0;

									tmp_borrow += rest;
								}
							}

							S.push_back(State(tmp_carry,tmp_borrow,tmp_carry+tmp_borrow+tmp_add));
						}

						for(int a = 0; a < S.size(); a++){
							if(S[a].tmp_borrow > num_R[col+1])continue;

							if(S[a].tmp_borrow == 0){

								if(work[CARRY][S[a].tmp_carry] > dp[pre][loop][i]+S[a].cost){
								//printf("CARRY:%dを%dで更新\n",S[a].tmp_carry,dp[pre][loop][i]+S[a].cost);

								work[CARRY][S[a].tmp_carry] = dp[pre][loop][i]+S[a].cost;
							}

							}else{
								if(work[BORROW][S[a].tmp_borrow] > dp[pre][loop][i]+S[a].cost){
									//printf("BORROW:%dを%dで更新\n",S[a].tmp_borrow,dp[pre][loop][i]+S[a].cost);
									work[BORROW][S[a].tmp_borrow] = dp[pre][loop][i]+S[a].cost;
								}
							}
						}
					}

			}

		}
		for(int num = 0; num < MAX; num++){
			dp[pre_pre][CARRY][num] = dp[pre][CARRY][num];
			dp[pre_pre][BORROW][num] = dp[pre][BORROW][num];

			dp[pre][CARRY][num] = work[CARRY][num];
			dp[pre][BORROW][num] = work[BORROW][num];


			DATA[pre_pre][num] = DATA[pre][num];
			DATA[pre][num] = work_DATA[num];
		}
	}

	printf("%d\n",dp[pre][CARRY][0]);

	return 0;
}
accuracy: 0.6857142857142857
time_ms: 220
memory_kb: 3532
final_rank: 7