极其仰慕 邝斌 巨巨!!!!!! Orz
资料
http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html
Problem List
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=23691#overview
Step By Step
A - Eat the Trees
最简单的,表示一下就行了。。
注意转移。
第一次照木板敲,以后就学会了把。。。
const int N = 20;
int n , m;
int code[N] , a[N][N];
const int HashSize = 1e4 + 9;
const int StateSize = 1e6 + 9;
struct HashMap{
int head[HashSize] , next[StateSize] , state[StateSize] , size;
LL f[StateSize];
void init(){
size = 0;
FLC(head , -1);
}
void push(int st , LL inc){
int h = st % HashSize;
for (int i = head[h] ; ~i ; i = next[i])
if (st == state[i]){
f[i] += inc;
return;
}
f[size] = inc;
state[size] = st;
next[size] = head[h];
head[h] = size++;
}
}H[2];
int encode(int * code , int m){
int st = 0;
for (int i = 0 ; i <= m ; ++i)
st = st << 1 | code[i];
return st;
}
void decode(int * code , int m , int st){
for (int i = m ; i >= 0 ; --i){
code[i] = st & 1;
st >>= 1;
}
}
void shift(int *code , int m){ // Another Line
for (int i = m ; i > 0 ; --i)
code[i] = code[i - 1];
code[0] = 0;
}
void dpblank(int x , int y , int cur){
int left , up;
for (int i = 0 ; i < H[cur].size ; ++i){
decode(code , m , H[cur].state[i]);
left = code[y - 1];
up = code[y];
if (left && up){ // 11 -> 00
code[y - 1] = code[y] = 0;
if (y == m) shift(code , m);
H[cur ^ 1].push( encode(code , m) , H[cur].f[i] );
}
else if (left || up){ // 10 | 01
if (a[x][y + 1]){ // Go right
code[y - 1] = 0;
code[y] = 1;
if (y == m) shift(code , m);
H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);
}
if (a[x + 1][y]){ // Go down
code[y - 1] = 1;
code[y] = 0;
if (y == m) shift(code , m);
H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);
}
}
else{ // 00
if (a[x][y + 1] && a[x + 1][y]){ // down to right
code[y] = code[y - 1] = 1;
H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);
}
}
}
}
void dpblock(int x , int y , int cur){
for (int i = 0 ; i < H[cur].size ; ++i){
decode(code , m , H[cur].state[i]);
code[y - 1] = code[y] = 0;
if (y == m) shift(code , m);
H[cur ^ 1].push(encode(code , m) , H[cur].f[i]);
}
}
int Case;
void solve(){
scanf("%d%d" , &n , &m);
for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j)
scanf("%d" , &a[i][j]);
for (int i = 1 ; i <= n ; ++i) a[i][0] = a[i][m + 1] = 0;
for (int i = 1 ; i <= m ; ++i) a[0][i] = a[n + 1][i] = 0;
LL ans = 0;
int cur = 0;
H[cur].init();
H[cur].push(0 , 1);
for (int i = 1 ; i <= n ; ++i) for (int j = 1 ; j <= m ; ++j){
H[cur ^ 1].init();
if (a[i][j]) dpblank(i , j , cur);
else dpblock(i , j , cur);
cur ^= 1;
}
for (int i = 0 ; i < H[cur].size ; i++)
ans += H[cur].f[i];
printf("Case %d: There are %I64d ways to eat the trees.\n",++Case , ans);
}
int main(){
int _;Case = 0;
cin >> _;
while(_--) solve();
}
B - Formula 1
三进制 -> 四进制的括号表示
括号表示还是相当快的!
http://blog.sina.com.cn/s/blog_51cea4040100gmky.html
这个blog 写的很清楚 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
struct Hashmap{
const static int HASHSIZE = 1e5 + 7;
const static int STATUSSIZE = 1e5 + 9;
int head[HASHSIZE];
struct hash_item{
int key;
LL val;
int next;
}item[STATUSSIZE + 1];
int L;
int getHash(int x){
return x % HASHSIZE;
}
void init(){
memset(head , -1 , sizeof(head));
L = 0;
}
void clear(){
for (int i = 0; i < L ; ++i)
head[getHash(item[i].key)] = -1;
L = 0;
}
int contains(int x){
for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)
if (item[i].key == x)
return i;
return -1;
}
void insert(int x){
int tmp = getHash(x);
item[L].key = x;
item[L].val = 0;
item[L].next = head[tmp];
head[tmp] = L++;
}
LL& operator[] (int x){
int tmp = contains(x);
if (tmp == -1){
insert(x);
return item[L - 1].val;
}
else return item[tmp].val;
}
}hm[2];
const int N = 15;
int n , m;
int code[N] , a[N][N];
int ex , ey;
char str[N];
void shift(int &code){
code <<= 2;
int mm = (m + 1) << 1;
code &= ((1 << mm) - 1);
}
int getplug(int cur , int y){
cur >>= 2 * y;
int ret = cur & 1;
cur >>= 1;
ret |= (cur & 1) << 1;
return ret;
}
void setplug(int &cur , int y , int key){
if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);
if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);
}
void dpblank(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left == 0 && up == 0){ //无插头,新建联通分量
if (a[x + 1][y] && a[x][y + 1]){
setplug(aft , y - 1 , 1);
setplug(aft , y , 2);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊
if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 (
int top = 0;
for (int j = y ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 1);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )
int top = 0;
for (int j = y - 1 ; j >= 0 ; --j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 2);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
else if (left == 1 && up == 2){ // () 只能在最后一个格子合并
if (x == ex && y == ey){
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left == 2 && up == 1){ // )( 维持原来状态
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else { // 有一个插头
if (left == 0 && up){
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
setplug(aft , y - 1 , up);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left && up == 0){
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
setplug(aft , y - 1 , 0);
setplug(aft , y , left);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
}
}
}
void dpblock(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left || up) continue;
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
void output(int code){
for (int i = 0 ; i <= m ; ++i){
int ret = code % 4;
code /= 4;
if (ret == 1) putchar('(');
else if (ret == 2) putchar(')');
else putchar('#');
}
}
void solve(){
RST(a);
for (int i = 1 ; i <= n; ++i){
scanf("%s" , str);
for(int j = 1 ; j <= m ; ++j){
a[i][j] = (str[j - 1] == '.');
if (a[i][j]){
ex = i , ey = j;
}
}
}
LL ans = 0;
int cur = 0;
hm[0].init();hm[1].init();
hm[0][0] = 1;
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j){
hm[cur ^ 1].clear();
if (a[i][j]) dpblank(i , j , cur);
else dpblock(i , j , cur);
cur ^= 1;
}
for (int i = 0 ; i < hm[cur].L ; ++i){
ans += hm[cur].item[i].val;
}
printf("%I64d\n" , ans);
}
int main(){
Case = 0;
while(~scanf("%d%d" , &n , &m)) solve();
}
C - Pandora adventure
跟上一题几乎一样。还是四进制括号表示法
但是有必须走和不是必须走的格子,改变两下——
1. 不必须走的 没有 left 和 up 插头可以继续扩展,忽略格子
2. 加入 是否形成圈 这个变量。
struct Hashmap{
const static int HASHSIZE = 1e3 + 7;
const static int STATUSSIZE = 1e5 + 9;
int head[HASHSIZE];
struct hash_item{
int key;
LL val;
int next;
}item[STATUSSIZE + 1];
int L;
int getHash(int x){
return x % HASHSIZE;
}
void init(){
memset(head , -1 , sizeof(head));
L = 0;
}
void clear(){
for (int i = 0; i < L ; ++i)
head[getHash(item[i].key)] = -1;
L = 0;
}
int contains(int x){
for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)
if (item[i].key == x)
return i;
return -1;
}
void insert(int x){
int tmp = getHash(x);
item[L].key = x;
item[L].val = 0;
item[L].next = head[tmp];
head[tmp] = L++;
}
LL& operator[] (int x){
int tmp = contains(x);
if (tmp == -1){
insert(x);
return item[L - 1].val;
}
else return item[tmp].val;
}
}hm[2];
const int N = 15;
int n , m;
int a[N][N];
int ex , ey;
char str[N];
int getplug(int cur , int y){
cur >>= 2 * y;
int ret = cur & 1;
cur >>= 1;
ret |= (cur & 1) << 1;
return ret;
}
int getcirlce(int cur){ // 加入连通记录,获取记录
int mm = (m + 1) << 1;
return (cur & (1 << mm)) != 0;
}
void setcircle(int &cur , int iscircle){ // 加入连通记录,改变
int mm = (m + 1) << 1;
if (((cur >> mm) & 1) != iscircle) cur ^= 1 << mm;
}
void shift(int &code){
int iscircle = getcirlce(code);
code <<= 2;
int mm = (m + 1) << 1;
code &= ((1 << mm) - 1);
setcircle(code , iscircle);
}
void setplug(int &cur , int y , int key){
if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);
if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);
}
void dpblank(int x , int y , int cur){
int left , up;
int aft;
int circle;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
circle = getcirlce(hm[cur].item[i].key);
if (left == 0 && up == 0){ //无插头,新建联通分量
if (a[x + 1][y] && a[x][y + 1]){
setplug(aft , y - 1 , 1);
setplug(aft , y , 2);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
aft = hm[cur].item[i].key;
if (a[x][y] == 2){ // 如果不是必须走的话就可以不扩展这个格子
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊
if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 (
int top = 0;
for (int j = y ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 1);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )
int top = 0;
for (int j = y - 1 ; j >= 0 ; --j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 2);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
else if (left == 1 && up == 2){ // () 只能在最后一个格子合并
if (!circle){ // 如果没有连通的话加入连通
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
setcircle(aft , 1);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left == 2 && up == 1){ // )( 维持原来状态
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else { // 有一个插头
if (left == 0 && up){
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
setplug(aft , y - 1 , up);
setplug(aft , y , 0);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
else if (left && up == 0){
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
setplug(aft , y - 1 , 0);
setplug(aft , y , left);
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
}
}
}
void dpblock(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left || up) continue;
if (y == m) shift(aft);
hm[cur ^ 1][aft] += hm[cur].item[i].val;
}
}
void output(int code){
for (int i = 0 ; i <= m ; ++i){
int ret = code % 4;
code /= 4;
if (ret == 1) putchar('(');
else if (ret == 2) putchar(')');
else putchar('#');
}
}
void solve(){
RD(n , m);
RST(a);
for (int i = 1 ; i <= n; ++i){
scanf("%s" , str);
for(int j = 1 ; j <= m ; ++j){
if (str[j - 1] == '*') a[i][j] = 2;
if (str[j - 1] == 'O') a[i][j] = 1;
}
}
LL ans = 0;
int cur = 0;
hm[0].init();hm[1].init();
hm[0][0] = 1;
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j){
hm[cur ^ 1].clear();
if (a[i][j]) dpblank(i , j , cur);
else dpblock(i , j , cur);
cur ^= 1;
}
for (int i = 0 ; i < hm[cur].L ; ++i) {
if (getcirlce(hm[cur].item[i].key)) ans += hm[cur].item[i].val;
}
printf("Case %d: %I64d\n" , ++Case , ans);
}
int main(){
Case = 0;
Rush solve();
}
D - Pipes
求单路径的最小分数。喜闻乐见直接套模板啊。
稍微改动的是求分数,val直接改成分数就好了。存在即有分,hashmap里面的状态都是可达的状态。
看下 喜闻乐见 的debug 方式
struct Hashmap{
const static int HASHSIZE = 1e4 + 7;
const static int STATUSSIZE = 1e5 + 9;
int head[HASHSIZE];
struct hash_item{
int key;
int val; // val 值改成最小分数 —— “存在”即有分,不用判断是否状态可达。在 hashmap 里面的状态都可达
int next;
}item[STATUSSIZE + 1];
int L;
int getHash(int x){
return x % HASHSIZE;
}
void init(){
memset(head , -1 , sizeof(head));
L = 0;
}
void clear(){
for (int i = 0; i < L ; ++i)
head[getHash(item[i].key)] = -1;
L = 0;
}
int contains(int x){
for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)
if (item[i].key == x)
return i;
return -1;
}
void insert(int x){
int tmp = getHash(x);
item[L].key = x;
item[L].val = 0;
item[L].next = head[tmp];
head[tmp] = L++;
}
void set(int x , int y){
int tmp = contains(x);
if (tmp == -1){
insert(x);
item[L - 1].val = y;
}
checkMin(item[tmp].val , y);
}
}hm[2];
const int N = 15;
int n , m;
int a[N][N];
int ex , ey;
char str[N<<1][N<<1];
PII score[N][N];
int getplug(int cur , int y){
cur >>= 2 * y;
int ret = cur & 1;
cur >>= 1;
ret |= (cur & 1) << 1;
return ret;
}
void shift(int &code){
code <<= 2;
int mm = (m + 1) << 1;
code &= ((1 << mm) - 1);
}
void setplug(int &cur , int y , int key){
if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);
if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);
}
void dpblank(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left == 0 && up == 0){ //无插头,新建联通分量
if (a[x + 1][y] && a[x][y + 1]){
setplug(aft , y - 1 , 1);
setplug(aft , y , 2);
if (y == m) shift(aft);
hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi + score[x][y].se);
}
}
else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊
if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 (
int top = 0;
for (int j = y ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 1);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val);
}
else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )
int top = 0;
for (int j = y - 1 ; j >= 0 ; --j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 2);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val);
}
else if (left == 1 && up == 2){ // () 只能在最后一个格子合并
if (x == ex && y == ey){ // 如果没有连通的话加入连通
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val);
}
}
else if (left == 2 && up == 1){ // )( 维持原来状态
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val);
}
}
else { // 有一个插头
if (left == 0 && up){
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
if (y == m) shift(aft);
//hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se);
}
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
setplug(aft , y - 1 , up);
setplug(aft , y , 0);
if (y == m) shift(aft);
//hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi);
}
}
else if (left && up == 0){
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].fi);
}
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
setplug(aft , y - 1 , 0);
setplug(aft , y , left);
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val + score[x][y].se);
}
}
}
}
}
void dpblock(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left || up) continue;
if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
hm[cur ^ 1].set(aft , hm[cur].item[i].val);
}
}
void output(int code){
for (int i = 0 ; i <= m ; ++i){
int ret = code % 4;
code /= 4;
if (ret == 1) putchar('(');
else if (ret == 2) putchar(')');
else putchar('#');
}
}
void solve(){
RD(n , m);
int line = 0;
gets(str[0]);
for (int i = 0 ; i < 2 * n + 1 ; ++i){
gets(str[i]);
if (!i) continue;
if (i & 1) line++;
if (i & 1){
for (int j = 1 ; j < m ; ++j)
score[line][j].se = str[i][j * 2] - '0';
}
else{
for (int j = 1 ; j <= m ; ++j)
score[line][j].fi = str[i][j * 2 - 1] - '0';
}
}
RST(a);
ex = n;ey = m;
for (int i = 1 ; i <= n; ++i){
for(int j = 1 ; j <= m ; ++j){
a[i][j] = 1;
}
}
int ans = INF;
int cur = 0;
hm[0].init();hm[1].init();
hm[0].set(0 , 0);
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j){
/**
比较喜闻乐见的 debug 方式
*/
// printf("Before %d %d\n" , i , j);
// for (int k = 0 ; k < hm[cur].L ; ++k){
// output(hm[cur].item[k].key);
// printf(":%d\t" , hm[cur].item[k].val);
// }
// puts("");
hm[cur ^ 1].clear();
dpblank(i , j , cur);
cur ^= 1;
// printf("After %d %d\n" , i , j);
// for (int k = 0 ; k < hm[cur].L ; ++k){
// output(hm[cur].item[k].key);
// printf(":%d\t" , hm[cur].item[k].val);
// }
// puts("");
}
for (int i = 0 ; i < hm[cur].L ; ++i)
checkMin(ans , hm[cur].item[i].val);
printf("%d\n" , ans);
}
int main(){
Case = 0;
Rush solve();
}
F - Tony's Tour
在有障碍的前提下,从左上走到右下的最小花费。
解法1:
加两行——
#..
...
变成
#..
...
.#.
...
解法2:
3进制正式变成 4 进制——独立插头
struct Hashmap{
const static int HASHSIZE = 681;
const static int STATUSSIZE = 1e4 + 9;
int head[HASHSIZE];
struct hash_item{
int key;
LL val;
int next;
}item[STATUSSIZE + 1];
int L;
int getHash(int x){
return x % HASHSIZE;
}
void init(){
memset(head , -1 , sizeof(head));
L = 0;
}
void clear(){
init();return;
for (int i = 0; i < L ; ++i)
head[getHash(item[i].key)] = -1;
L = 0;
}
int contains(int x){
for (int i = head[getHash(x)]; i != -1 ; i = item[i].next)
if (item[i].key == x)
return i;
return -1;
}
void insert(int x){
int tmp = getHash(x);
item[L].key = x;
item[L].val = 0;
item[L].next = head[tmp];
head[tmp] = L++;
}
LL& operator[] (int x){
int tmp = contains(x);
if (tmp == -1){
insert(x);
return item[L - 1].val;
}
else return item[tmp].val;
}
}hm[2];
const int N = 15;
int n , m;
int code[N] , a[N][N];
int ex , ey;
char str[N];
void shift(int &code){
code <<= 2;
int mm = (m + 1) << 1;
code &= ((1 << mm) - 1);
}
int getplug(int cur , int y){
cur >>= 2 * y;
int ret = cur & 3;
return ret;
}
void setplug(int &cur , int y , int key){
if ( ((cur >> (y << 1)) & 1) ^ (key & 1) ) cur ^= 1 << (y << 1);
if ( ((cur >> (y << 1 | 1)) & 1) ^ ((key >> 1) & 1) ) cur ^= 1 << (y << 1 | 1);
}
bool canbeSinglePlug(int x , int y){
if (x == n) return y == 1 || y == m;
return false;
}
void UPD(LL &x , LL y){
x += y;
}
void dpblank(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left == 0 && up == 0){ //无插头,新建联通分量
if (a[x + 1][y] && a[x][y + 1]){
setplug(aft , y - 1 , 1);
setplug(aft , y , 2);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
if (canbeSinglePlug(x , y)){ // 如果能形成独立插头
if (a[x + 1][y]){
aft = hm[cur].item[i].key;
setplug(aft , y - 1 , 3);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
if (a[x][y + 1]){
aft = hm[cur].item[i].key;
setplug(aft , y - 1 , 0);
setplug(aft , y , 3);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
}
else if (left && up){ // 有两个插头 ! 要删掉上插头和左插头啊
if (left == 3 && up == 3){ // 如果都是独立插头,那么只能在最后一个格子里面合并
if (x == ex && y == ey){
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
else if (left == 3 || up == 3){ // 如果有一个 独立插头那么,将对应的插头改为独立插头
int other = left + up - 3;
if (other == 1){
int top = 1;
for (int j = y + 1; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 3);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
else if (other == 2){
int top = 1;
for (int j = y - 2 ; j >= 0 ; --j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 3);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
else if (left == 1 && up == 1){ // (( 找到下一个对应的 ) 改成 (
int top = 0;
for (int j = y ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 1);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
else if (left == 2 && up == 2){ // )) 找到上一个对应的 ( 变成 )
int top = 0;
for (int j = y - 1 ; j >= 0 ; --j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 2);
break;
}
}
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
else if (left == 1 && up == 2){ // () 只能在最后一个格子合并
// if (x == ex && y == ey){ // 不可能发生
// setplug(aft , y - 1 , 0);
// setplug(aft , y , 0);
// if (y == m) shift(aft);
// hm[cur ^ 1][aft] += hm[cur].item[i].val;
// }
}
else if (left == 2 && up == 1){ // )( 维持原来状态
setplug(aft , y - 1 , 0);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
else { // 有一个插头
if (left + up == 3){ // 如果只有一个独立插头
if (x == ex && y == ey){ //那么可以在最后一个非障碍格子中成为另一端
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
else{ // 或者用下插头 或者 有插头 延续独立插头
aft = hm[cur].item[i].key;
if(a[x + 1][y]){
setplug(aft , y - 1 , 3);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
aft = hm[cur].item[i].key;
if(a[x][y + 1]){
setplug(aft , y - 1 , 0);
setplug(aft , y , 3);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
}
else{
if (canbeSinglePlug(x , y)){ // 将当前插头封住,另一端成为独立插头
int thisplug = left + up;
setplug(aft , y - 1 , 0);
setplug(aft, y , 0);
if (thisplug == 1){
int top = 1;
for (int j = y + 1 ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 1) ++top;
if (plug == 2) --top;
if (top == 0){
setplug(aft , j , 3);
break;
}
}
}
else if (thisplug == 2){
int top = 1;
for (int j = y - 2 ; j <= m ; ++j){
int plug = getplug(hm[cur].item[i].key , j);
if (plug == 2) ++top;
if (plug == 1) --top;
if (top == 0){
setplug(aft , j , 3);
break;
}
}
}
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
aft = hm[cur].item[i].key;
if (left == 0 && up){
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
setplug(aft , y - 1 , up);
setplug(aft , y , 0);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
else if (left && up == 0){
aft = hm[cur].item[i].key;
if (a[x + 1][y]){
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
aft = hm[cur].item[i].key;
if (a[x][y + 1]){
setplug(aft , y - 1 , 0);
setplug(aft , y , left);
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
}
}
}
}
void dpblock(int x , int y , int cur){
int left , up;
int aft;
for (int i = 0 ; i < hm[cur].L ; ++i) if (hm[cur].item[i].val){
aft = hm[cur].item[i].key;
left = getplug(hm[cur].item[i].key , y - 1);
up = getplug(hm[cur].item[i].key , y);
if (left || up) continue;
if (y == m) shift(aft);
UPD(hm[cur ^ 1][aft] , hm[cur].item[i].val);
}
}
void output(int code){
for (int i = 0 ; i <= m ; ++i){
int ret = code % 4;
code /= 4;
if (ret == 1) putchar('(');
else if (ret == 2) putchar(')');
else if (ret == 3) putchar('|');
else putchar('#');
}
}
void solve(){
RST(a);
for (int i = 1 ; i <= n; ++i){
scanf("%s" , str);
for(int j = 1 ; j <= m ; ++j){
a[i][j] = (str[j - 1] == '.');
if (a[i][j]){
ex = i , ey = j;
}
}
}
ex = n , ey = m;
LL ans = 0;
int cur = 0;
hm[0].init();hm[1].init();
hm[0][0] = 1;
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j){
hm[cur ^ 1].clear();
if (a[i][j]) dpblank(i , j , cur);
else dpblock(i , j , cur);
cur ^= 1;
// printf("%d %d:\n" , i , j); // debug 方法,输出 插头形式
// for (int k = 0 ; k < hm[cur].L ; ++k){
// output(hm[cur].item[k].key);printf(":%lld\t" , hm[cur].item[k].val);
// }
// puts("");
}
for (int i = 0 ; i < hm[cur].L ; ++i){
ans += hm[cur].item[i].val;
}
printf("%lld\n" , ans);
}
int main(){
Case = 0;
while(~scanf("%d%d" , &n , &m) && n && m) solve();
}