## 题目描述

There is a rectangular area containing $n \times m$ cells. Two cells are marked with “2”, and another two with “3”. Some cells are occupied by obstacles. You should connect the two “2”s and also the two “3”s with non-intersecting lines. Lines can run only vertically or horizontally connecting centers of cells without obstacles.
Lines cannot run on a cell with an obstacle. Only one line can run on a cell at most once. Hence, a line cannot intersect with the other line, nor with itself. Under these constraints, the total length of the two lines should be minimized. The length of a line is defined as the number of cell borders it passes. In particular, a line connecting cells sharing their border has length $1$.
Fig. 1(a) shows an example setting. Fig. 1(b) shows two lines satisfying the constraints above with minimum total length $18$.

## 代码

#include <cstdio>
#include <cstring>

void minify(short &a, short b) {
a > b && (a = b);
}

static const int N = 11;
int rec[1 << 20];
short mp[N][N], f[2][N][1 << 20]; // 0 for no wire, 2 for wire 2, 3 for wire 3

int modify(int s, int p, int v) {
return (s & ((1 << (p << 1)) - 1)) | (((s >> ((p + 1) << 1) << 2) + v) << (p << 1));
}

int query(int s, int p) {
return s >> (p << 1) & 3;
}

int main() {
int n, m, top = 0;
for (int i = 0; i < 1 << 20; ++ i) {
for (int j = 0; j < N; ++ j) if (query(i, j) == 1) goto illegal;
rec[top ++] = i; illegal: ;
}
while (scanf("%d%d", &n, &m), n) {
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j) scanf("%hd", &mp[i][j]);
int cur = 0; memset(f, 0x3f, sizeof f), f[cur][0][0] = 0;
for (int i = 0; i < n; ++ i, cur ^= 1) {
for (int j = 0; j < m; ++ j)
for (int _ = 0, k = rec[0]; _ < top; k = rec[++ _])
if (f[cur][j][k] < 10000) {
int p = query(k, j), q = query(k, j + 1);
if (mp[i][j] == 0) {
if (! p && ! q)
minify(f[cur][j + 1][k], f[cur][j][k]),
minify(f[cur][j + 1][modify(modify(k, j, 2), j + 1, 2)], f[cur][j][k] + 1),
minify(f[cur][j + 1][modify(modify(k, j, 3), j + 1, 3)], f[cur][j][k] + 1);
else if (! p ^ ! q)
minify(f[cur][j + 1][modify(modify(k, j, p + q), j + 1, 0)], f[cur][j][k] + 1),
minify(f[cur][j + 1][modify(modify(k, j, 0), j + 1, p + q)], f[cur][j][k] + 1);
else if (p && p == q)
minify(f[cur][j + 1][modify(modify(k, j, 0), j + 1, 0)], f[cur][j][k] + 1);
} else if (mp[i][j] == 1) {
if (! p && ! q) minify(f[cur][j + 1][k], f[cur][j][k]);
} else {
if (! p && ! q)
minify(f[cur][j + 1][modify(k, j, mp[i][j])], f[cur][j][k] + 1),
minify(f[cur][j + 1][modify(k, j + 1, mp[i][j])], f[cur][j][k] + 1);
else if (p == mp[i][j] && ! q)
minify(f[cur][j + 1][modify(k, j, 0)], f[cur][j][k] + 1);
else if (! p && q == mp[i][j])
minify(f[cur][j + 1][modify(k, j + 1, 0)], f[cur][j][k] + 1);
}
}
for (int _ = 0, k = rec[0]; _ < top; k = rec[++ _])
if (! query(k, m)) minify(f[cur ^ 1][0][k << 2 & (1 << ((m + 1) << 1)) - 1], f[cur][m][k]);
for (int j = 0; j <= m; ++ j)
for (int _ = 0, k = rec[0]; _ < top; k = rec[++ _]) f[cur][j][k] = 16000;
}
printf("%d\n", f[cur][0][0] < 10000 ? f[cur][0][0] - 2 : 0);
}
return 0;
}


## 题目描述

Bob really LOVES chocolate. He thinks he never gets enough. Imagine his joy when his parents told him that they would buy him many rectangular chocolate pieces for his birthday. A piece of chocolate is a $2 \times 1$ or $1 \times 2$ rectangle. Bob’s parents also bought him a nice birthday cake, which can be imagined as a matrix having $M$ rows and $N$ columns. Some positions on the cake are occupied by candles, the others are empty. Bob’s parents asked their son to place as many chocolate pieces as he can on the empty squares on the cake, in such a manner that no two chocolate pieces overlap. However, he would like to keep the chocolate pieces to himself. That’s why, he wants to place only a minimal amount of them on the cake and keep the rest. In order not to make Mon and Dad suspicious, Bob wants to place the chocolate pieces in such a way, that no other piece may be placed on the cake (that is, there won’t exist any two adjacent empty squares). Find the minimal number of pieces which need to be placed on the cake, so that they do not overlap and no extra piece may be added.

## 代码

#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

namespace std {
template <typename T> void maxify(T &a, T b) { b > a && (a = b); }
template <typename T> void minify(T &a, T b) { b < a && (a = b); }
}

struct IOManager {
template <typename T> inline bool read(T &x) { char c = '\n'; bool flag = false; x = 0; while (~ c && ! isdigit(c = getchar()) && c != '-') ; c == '-' && (flag = true, c = getchar()); if (! ~ c) return false; while (isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = getchar(); return (flag && (x = -x), true); }
inline bool read(char &c) { c = '\n'; while (~ c && ! (isprint(c = getchar()) && c != ' ')) ; return ~ c; }
inline int read(char s[]) { char c = '\n'; int len = 0; while (~ c && ! (isprint(c = getchar()) && c != ' ')) ; if (! ~ c) return 0; while (isprint(c) && c != ' ') s[len ++] = c, c = getchar(); return (s[len] = '\0', len); }
template <typename T> inline IOManager operator > (T &x) { read(x); return *this; }
template <typename T> inline void write(T x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); }
inline void write(char c) { putchar(c); }
inline void write(char s[]) { int pos = 0; while (s[pos] != '\0') putchar(s[pos ++]); }
template <typename T> inline IOManager operator < (T x) { write(x); return *this; }
} io;

struct Solver {
private:
static const int N = 80;
static const int M = 8;
int n, m, f[2][1 << M][1 << M], mp[N];
void input() {
io > n > m;
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= m; ++ j) {
char c; io > c, (mp[i] <<= 1) += c == '*';
}
mp[0] = mp[n + 1] = mp[n + 2] = (1 << m) - 1;
}
void init() { memset(f, 0x1f, sizeof f), f[0][mp[0]][mp[1]] = 0; }
bool check(int s) {
bool flag = false;
for (int i = 0; i < m; s >>= 1, ++ i) {
if (s & 1) flag = false;
else { if (flag) return false; flag = true; }
}
return true;
}
void update(int x, int a, int b, int s, int val, int p) {
if (check(b) && ! ((1 << m) - 1 - a & (1 << m) - 1 - b)) minify(f[x][b][s], val);
for (int i = p; i < m; ++ i)
if (! (b & 1 << i)) {
if (! (s & 1 << i)) update(x, a, b | 1 << i, s | 1 << i, val + 1, i + 1);
if (i && ! (b & 1 << i - 1)) update(x, a, b | 1 << i | 1 << i - 1, s, val + 1, i + 1);
}
}
void process() {
int cur = 0;
for (int i = 1; i <= n + 1; cur ^= 1, ++ i) {
memset(f[cur ^ 1], 0x1f, sizeof f[cur ^ 1]);
for (int j = 0; j < 1 << m; ++ j)
for (int k = 0; k < 1 << m; ++ k)
if (f[cur][j][k] < 5e8) update(cur ^ 1, j, k, mp[i + 1], f[cur][j][k], 0);
}
io < f[cur][(1 << m) - 1][(1 << m) - 1] < '\n';
}

public:
void solve() { input(), init(), process(); }
} solver;

int main() {
solver.solve();
return 0;
}


## 题目描述

The banquet hall of Computer Scientists’ Palace has a rectangular form of the size $M \times N$. It is necessary to lay hardwood floors in the hall. There are wood pieces of two forms:

• rectangles ($2 \times 1$)
• corners (squares $2 \times 2$ without one $1 \times 1$ square)

You have to determine $X$ – the number of ways to cover the banquet hall.
Remarks. The number of pieces is large enough. It is not allowed to leave empty places, or to cover any part of a surface twice, or to saw pieces.

## 代码

#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define int long long

using namespace std;

struct IOManager {
template <typename T> inline bool read(T &x) { char c = '\n'; bool flag = false; x = 0; while (~ c && ! isdigit(c = getchar()) && c != '-') ; c == '-' && (flag = true, c = getchar()); if (! ~ c) return false; while (isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = getchar(); return (flag && (x = -x), true); }
inline bool read(char &c) { c = '\n'; while (~ c && ! (isprint(c = getchar()) && c != ' ')) ; return ~ c; }
inline int read(char s[]) { char c = '\n'; int len = 0; while (~ c && ! (isprint(c = getchar()) && c != ' ')) ; if (! ~ c) return 0; while (isprint(c) && c != ' ') s[len ++] = c, c = getchar(); return (s[len] = '\0', len); }
template <typename T> inline IOManager operator > (T &x) { read(x); return *this; }
template <typename T> inline void write(T x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); }
inline void write(char c) { putchar(c); }
inline void write(char s[]) { int pos = 0; while (s[pos] != '\0') putchar(s[pos ++]); }
template <typename T> inline IOManager operator < (T x) { write(x); return *this; }
} io;

struct Solver {
private:
static const int N = 11;
int n, m, f[N][1 << N];
void input() { io > n > m; }
void update(int x, int y, int s, int val, int p) {
if (y == (1 << m) - 1) { f[x][s] += val; return; }
for (int i = p; i < m; ++ i)
if (! (y & 1 << i)) {
if (! (s & 1 << i)) {
update(x, y | 1 << i, s | 1 << i, val, i + 1);
if (i && ! (s & 1 << i - 1)) update(x, y | 1 << i, s | 1 << i | 1 << i - 1, val, i + 1);
if (i < m - 1 && ! (s & 1 << i + 1)) update(x, y | 1 << i, s | 1 << i | 1 << i + 1, val, i + 1);
}
if (i < m - 1 && ! (y & 1 << i + 1)) {
update(x, y | 1 << i | 1 << i + 1, s, val, i + 2);
if (! (s & 1 << i)) update(x, y | 1 << i | 1 << i + 1, s | 1 << i, val, i + 2);
if (! (s & 1 << i + 1)) update(x, y | 1 << i | 1 << i + 1, s | 1 << i + 1, val, i + 2);
}
}
}
void process() {
f[0][(1 << m) - 1] = 1;
for (int i = 0; i <= n; ++ i)
for (int j = 0; j < 1 << m; ++ j)
if (f[i][j]) update(i + 1, j, 0, f[i][j], 0);
io < f[n + 1][0] < '\n';
}

public:
void solve() { input(), process(); }
} solver;

signed main() {
solver.solve();
return 0;
}


## 题目描述

There is a syntactically correct boolean expression.
The definition of syntactically correct expression follows as:

1. “a”, “b”, “c”, …, “j” are syntactically correct expressions.
2. If A is a correct expression, then !A and (A) are correct expressions too.
3. If A is a correct expression and B is a correct expression, then A||B, A&B, A<=>B, A=>B, A#B are syntactically correct expressions too.

Syntactically correct expression doesn’t contain spaces.
Small Latin letters are variables, ! denotes negation, || – disjunction, & – conjunction, <=> – equality, => – implication, # – excepting or.
Negation has the highest priority, conjunction has middle priority, and other operations have low priority. Brackets change the order of operations executing.
Two expressions are called identical if their values are the same in any values of variables.
Make the expression, which will be identical with given expression. New expression must be free of brackets.

## 代码

#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <stack>

using namespace std;

struct Solver {
private:
string s;
void input() { cin >> s; }
int len(char c) {
switch (c) {
case '!' : return 0;
case '&' : return 0;
case '|' : return 1;
case '<' : return 2;
case '=' : return 1;
case '#' : return 0;
}
}
int priority(char c) {
switch (c) {
case '!' : return 1;
case '&' : return 2;
case '|' : return 3;
case '<' : return 3;
case '=' : return 3;
case '#' : return 3;
case '(' : return 4;
}
}
bool single(bool a, char c, bool b) {
switch (c) {
case '&' : return a && b;
case '|' : return a || b;
case '<' : return a == b;
case '=' : return a || ! b;
case '#' : return a ^ b;
}
}
int match(string s, int p) {
int cnt = 1;
while (cnt) ++ p, cnt += (s[p] == '(') - (s[p] == ')');
return p;
}
stack <char> symbol;
stack <bool> number;
void pop() {
if (symbol.top() == '!') {
symbol.pop(); bool p = number.top(); number.pop(), number.push(! p);
} else {
bool p = number.top(); number.pop();
bool q = number.top(); number.pop();
number.push(single(p, symbol.top(), q));
symbol.pop();
}
}
bool calc(string s) {
for (int i = 0; i < s.length(); ++ i) {
if (isdigit(s[i])) number.push(s[i] - '0');
else if (s[i] == '(') symbol.push('(');
else if (s[i] == ')') {
while (symbol.top() != '(') pop();
symbol.pop();
} else {
while (! symbol.empty() && priority(symbol.top()) <= priority(s[i])) pop();
symbol.push(s[i]), i += len(s[i]);
}
}
while (! symbol.empty()) pop();
return number.top();
}
bool check(int p, string s) {
for (int i = 0; i < s.length(); ++ i)
if (isalpha(s[i])) s[i] = ((p & 1 << s[i] - 'a') > 0) + '0';
return calc(s);
}
void process() {
for (int i = 0; i + 1 < s.length(); ++ i)
while (i + 1 < s.length() && s[i] == '!' && s[i + 1] == '!')
s = s.substr(0, i) + s.substr(i + 2);
string ans, sep;
for (int i = 0; i < 1 << 10; ++ i)
if (check(i, s)) {
ans += sep, sep = "||";
string s;
for (int j = 0; j < 10; ++ j) {
ans += s, s = "&";
if (! (i & 1 << j)) ans += "!";
ans += j + 'a';
}
}
if (ans.length() == 0) ans = "!a&a";
cout << ans << endl;
}

public:
void solve() { input(), process(); }
} solver;

int main() {
solver.solve();
return 0;
}


## 题目描述

Mojtaba and Arpa are playing a game. They have a list of $n$ numbers in the game.
In a player’s turn, he chooses a number $p^k$ (where $p$ is a prime number and $k$ is a positive integer) such that $p^k$ divides at least one number in the list. For each number in the list divisible by $p^k$, call it $x$, the player will delete $x$ and add ${x \over p^k}$ to the list. The player who can not make a valid choice of $p$ and $k$ loses.
Mojtaba starts the game and the players alternatively make moves. Determine which one of players will be the winner if both players play optimally.

## 代码

#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

namespace std {
template <typename T>
void maxify(T &a, T b) { b > a && (a = b); }
template <typename T>
void minify(T &a, T b) { b < a && (a = b); }
}

struct IOManager {
template <typename T>
char c; bool flag = false; x = 0;
while (~ c && ! isdigit(c = getchar()) && c != '-') ;
c == '-' && (flag = true, c = getchar());
if (! ~ c) return false;
while (isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = getchar();
return (flag && (x = -x), true);
}
c = '\n';
while (~ c && ! (isprint(c = getchar()) && c != ' ')) ;
return ~ c;
}
char c; int len = 0;
while (~ c && ! (isprint(c = getchar()) && c != ' ')) ;
if (! ~ c) return 0;
while (isprint(c) && c != ' ') s[len ++] = c, c = getchar();
return (s[len] = '\0', len);
}
template <typename T>
inline IOManager operator > (T &x) {
}
template <typename T>
inline void write(T x) {
x < 0 && (putchar('-'), x = -x);
x > 9 && (write(x / 10), true);
putchar(x % 10 + '0');
}
inline void write(char c) {
putchar(c);
}
inline void write(char s[]) {
int pos = 0;
while (s[pos] != '\0') putchar(s[pos ++]);
}
template <typename T>
inline IOManager operator < (T x) {
write(x); return *this;
}
} io;

struct Solver {
private:
static const int N = 100;
int n, a[N + 1];
map <int, int> sg, num;
void input() {
io > n;
for (int i = 1; i <= n; ++ i) io > a[i];
}
void init() {
for (int i = 1; i <= n; ++ i)
if (a[i] > 1) {
int q = sqrt(a[i]);
for (int j = 2; j <= q; ++ j) {
if (a[i] == 1) break;
if (! (a[i] % j)) {
int cnt = 0;
while (! (a[i] % j)) a[i] /= j, ++ cnt;
num[j] |= 1 << cnt - 1;
}
}
if (a[i] > 1) num[a[i]] |= 1;
}
}
int get_sg(int t) {
if (! t) return 0;
if (sg.count(t)) return sg[t];
map <int, bool> vis;
int p = t, cnt = 0;
while (p) p >>= 1, ++ cnt;
for (int i = 1; i <= cnt; ++ i)
vis[get_sg((t >> i) | (t & (1 << i - 1) - 1))] = true;
cnt = 0;
while (vis[cnt]) ++ cnt;
return sg[t] = cnt;
}
void process() {
int ans = 0;
for (map <int, int> :: iterator it = num.begin(); it != num.end(); ++ it) ans ^= get_sg(it->second);
if (! ans) io < (char *) "Arpa\n";
else io < (char *) "Mojtaba\n";
}

public:
void solve() {
input(), init(), process();
}
} solver;

int main() {
solver.solve();
return 0;
}


## 题目描述

$T$ is a complete binary tree consisting of $n$ vertices. It means that exactly one vertex is a root, and each vertex is either a leaf (and doesn’t have children) or an inner node (and has exactly two children). All leaves of a complete binary tree have the same depth (distance from the root). So $n$ is a number such that $n+1$ is a power of $2$.
In the picture you can see a complete binary tree with $n=15$.

Vertices are numbered from $1$ to $n$ in a special recursive way: we recursively assign numbers to all vertices from the left subtree (if current vertex is not a leaf), then assign a number to the current vertex, and then recursively assign numbers to all vertices from the right subtree (if it exists). In the picture vertices are numbered exactly using this algorithm. It is clear that for each size of a complete binary tree exists exactly one way to give numbers to all vertices. This way of numbering is called symmetric.
You have to write a program that for given $n$ answers $q$ queries to the tree.
Each query consists of an integer number $u_i$ and a string $s_i$, where $u_i$ is the number of vertex, and $s_i$ represents the path starting from this vertex. String $s_i$ doesn’t contain any characters other than $L, R$ and $U$, which mean traverse to the left child, to the right child and to the parent, respectively. Characters from $s_i$ have to be processed from left to right, considering that $u_i$ is the vertex where the path starts. If it’s impossible to process a character (for example, to go to the left child of a leaf), then you have to skip it. The answer is the number of vertex where the path represented by $s_i$ ends.
For example, if $u_i=4$ and $s_i=UURL$, then the answer is $10$.

## 算法分析

$\because j$的右子树在$j$的右边，且在$i$的左边.
$\therefore (i-1)-j=s_j$.
$j=i-lowbit_j$.

$\therefore lowbit_i=2lowbit_j$.
$j=i-{lowbit_i \over 2}$.

$\because j$的左子树在$j$的左边，且在$i$的右边.
$\therefore (j-1)-i=s_j$.
$j=i+lowbit_j$.

$\therefore lowbit_i=2lowbit_j$.
$j=i+{lowbit_i \over 2}$.

①$i$在$j$左边.
$\because$等价于$L$操作的逆操作.
$\therefore i=j-lowbit_i$.
$j=i+lowbit_i$.
②$i$在$j$右边.
$\because$等价于$R$操作的逆操作.
$\therefore i=j+lowbit_i$.
$j=i-lowbit_i$.

## 代码

#include <iostream>
using namespace std;
long long n, t, p, len;
string s;
long long lowbit(long long t) {
return t & -t;
}
int main()
{
cin >> n >> t;
while (t--) {
cin >> p >> s;
len = s.length();
for (int i = 0; i < len; ++i) {
long long q = lowbit(p);
switch (s[i]) {
case 'U': {
if (p != n + 1 >> 1) {
p -= q;
p |= q << 1;
}
break;
}
case 'L': {
if (!(p & 1)) {
p -= q >> 1;
}
break;
}
case 'R': {
if (!(p & 1)) {
p += q >> 1;
}
break;
}
}
}
cout << p << endl;
}
return 0;
}