foj 1977 Pandora adventure(插头DP)

21 篇文章 0 订阅
7 篇文章 0 订阅

哎。。。。。哭

都是泪。。。。。哭

这游戏太难了。。。。哭

再一次写了三天才AC。。。哭

生活为什么要这么艰难。。。。哭




妈蛋的啊。。。。

经过这一题之后我对插头DP理解更深了。。。。。只要是形成回路之后就不用再添加到装态里去了。。。。。。。

这次的代码也比前几次漂亮了不少,

当然是因为借鉴了别人的写法

AC代码如下:

四进制

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const __int64 digit[15] = { 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969 };

const int mod = 10007;

struct HASHS{
    __int64 statu[80010], cnt[80010];
    int head[mod+10], next[80010], E;

    int findhash( __int64 st ){
        return st % mod;
    }

    void init(){
        E = 0;
        memset( head, -1, sizeof( head ) );
    }

    void add( __int64 st, __int64 num ){
        int u = findhash( st );
        for( int i = head[u]; i != -1; i = next[i] ){
            if( statu[i] == st ){
                cnt[i] += num;
                return;
            }
        }
        statu[E] = st;
        cnt[E] = num;
        next[E] = head[u];
        head[u] = E++;
    }
}biao[2];

int N, M;
char s[16][16];

int get( __int64 S,int p,int l=2)
{
	return (S>>(p*l))&((1<<l)-1);
}

void set( __int64 &S,int p,int v,int l=2)
{
	S^=get(S,p,l)<<(p*l);
	S^=(v&((1<<l)-1))<<(p*l);
}

int find_r( int st, int j ){
    int temp = 0, l;
    for( l = j + 1; l <= M; l++ ){
        __int64 ttt = get( st, l );
        if( ttt == 2 ){
            if( temp == 0 ){
                break;
            }else{
                temp--;
            }
        }else if( ttt == 1 ){
            temp++;
        }
    }
    return l;
}

int find_l( int st, int j ){
    int temp = 0, l;
    for( l = j - 1; l >= 0; l-- ){
        __int64 ttt = get( st, l );
        if( ttt == 1 ){
            if( temp == 0 ){
                break;
            }else{
                temp--;
            }
        }else if( ttt == 2 ){
            temp++;
        }
    }
    return l;
}


__int64 solve(){
    int now;
    now = 1;
	int lasti, lastj;
	lasti = -1;
	lastj = 1;
	int flag = 1;
	for( int i = N; i >= 1 && flag; i-- ){
		for( int j = M; j >= 1 && flag; j-- ){
			if( s[i][j] == 'O' ){
				lasti = i;
				lastj = j;
				flag = 0;
			}
		}
	}
	__int64 ans = 0;
    biao[0].init();
    biao[1].init();
    biao[1].add( 0, 1 );
    now = 0;
    for( int i = 1; i <= N; i++ ){
        now ^= 1;
        biao[now^1].init();
        for( int k = 0; k < biao[now].E; k++ ){
            __int64 st = biao[now].statu[k];
			__int64 sum = biao[now].cnt[k];
            biao[now^1].add( st << 2, sum );
        }
        for( int j = 0; j < M; j++ ){
            now ^= 1;
            biao[now^1].init();
            for( int k = 0; k < biao[now].E; k++ ){

                __int64 st = biao[now].statu[k];
                __int64 sum = biao[now].cnt[k];
                __int64 numj = get( st, j );
                __int64 numj_1 = get( st, j + 1 );

                if( s[i][j+1] == 'O' || s[i][j+1] == '*' ){
                    if( numj == 0 && numj_1 == 0 ){
                        if( s[i][j+1] == '*' )  biao[now^1].add( st, sum );
                        set( st, j, 1 );
                        set( st, j + 1, 2 );
                        if( j + 1 < M && s[i+1][j+1] != 'X' && s[i][j+2] != 'X' ) biao[now^1].add( st, sum );
                    }else if( numj == 0 || numj_1 == 0 ){
                        set( st, j, 0 );
                        set( st, j + 1, numj + numj_1 );
                        if( j + 1 < M && s[i][j+2] != 'X' ) biao[now^1].add( st, sum );
                        set( st, j, numj + numj_1 );
                        set( st, j + 1, 0 );
                        if( s[i+1][j+1] != 'X' ) biao[now^1].add( st, sum );
                    }else{
                        if( numj == 1 && numj_1 == 1 ){
                            int l = find_r( st, j + 1 );
                            if( l <= M ){
                                set( st, l, 1 );
                                set( st, j, 0 );
                                set( st, j + 1, 0 );
                                biao[now^1].add( st, sum );
                            }
                        }else if( numj == 2 && numj_1 == 2 ){
                            int l = find_l( st, j );
                            if( l >= 0 ){
                                set( st, l, 2 );
                                set( st, j, 0 );
                                set( st, j + 1, 0 );
                                biao[now^1].add( st, sum );
                            }
                        }else if( numj == 2 && numj_1 == 1 ){
                            set( st, j, 0 );
                            set( st, j + 1, 0 );
                            biao[now^1].add( st, sum );
                        }else{
                            set( st, j, 0 );
                            set( st, j + 1, 0 );
                            if( ( i > lasti || ( i == lasti && j + 1 >= lastj ) ) && !st ){
                                ans += sum;
                            }
                        }
                    }

                }else{
                    if( numj == 0 && numj_1 == 0 ){
                        biao[now^1].add( st, sum );
                    }
                }
            }
        }
    }
    return ans;
}

int main(){
    int T, Case = 1;
    cin >> T;
    while( T-- ){
        scanf( "%d%d", &N, &M );
		memset( s, 0, sizeof( s ) );
        for( int i = 1; i <= N; i++ ){
            scanf( "%s", &s[i][1] );
        }
        printf( "Case %d: %I64d\n", Case++, solve() );
    }
    return 0;
}

三进制

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const __int64 digit[15] = { 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969 };

const int mod = 10007;

struct HASHS{
    __int64 statu[80010], cnt[80010];
    int head[mod+10], next[80010], E;

    int findhash( __int64 st ){
        return st % mod;
    }

    void init(){
        E = 0;
        memset( head, -1, sizeof( head ) );
    }

    void add( __int64 st, __int64 num ){
        int u = findhash( st );
        for( int i = head[u]; i != -1; i = next[i] ){
            if( statu[i] == st ){
                cnt[i] += num;
                return;
            }
        }
        statu[E] = st;
        cnt[E] = num;
        next[E] = head[u];
        head[u] = E++;
    }
}biao[2];

int N, M;
char s[16][16];

int get( int k, int st ){
    return ( st % digit[k+1] ) / digit[k];
}

int find_r( int st, int j ){
    int temp = 0, l;
    for( l = j + 1; l <= M; l++ ){
        __int64 ttt = ( st % digit[l+1] ) / digit[l];
        if( ttt == 2 ){
            if( temp == 0 ){
                break;
            }else{
                temp--;
            }
        }else if( ttt == 1 ){
            temp++;
        }
    }
    return l;
}

int find_l( int st, int j ){
    int temp = 0, l;
    for( l = j - 1; l >= 0; l-- ){
        __int64 ttt = ( st % digit[l+1] ) / digit[l];
        if( ttt == 1 ){
            if( temp == 0 ){
                break;
            }else{
                temp--;
            }
        }else if( ttt == 2 ){
            temp++;
        }
    }
    return l;
}

__int64 solve(){
	int now;
	int lasti, lastj;
	lasti = -1;
	lastj = 1;
	int flag = 1;
	for( int i = N; i >= 1 && flag; i-- ){
		for( int j = M; j >= 1 && flag; j-- ){
			if( s[i][j] == 'O' ){
				lasti = i;
				lastj = j;
				flag = 0;
			}
		}
	}
	__int64 ans = 0;
//	if( lasti == -1 ){
 //       ans += 1;
//	}
	biao[0].init();
    biao[1].init();
    biao[1].add( 0, 1 );
    now = 0;
    for( int i = 1; i <= N; i++ ){
        now ^= 1;
        biao[now^1].init();
        for( int k = 0; k < biao[now].E; k++ ){
            __int64 st = biao[now].statu[k];
			__int64 sum = biao[now].cnt[k];
            biao[now^1].add( st * 3, sum );
        }
        for( int j = 0; j < M; j++ ){
            now ^= 1;
            biao[now^1].init();
            for( int k = 0; k < biao[now].E; k++ ){

                __int64 st = biao[now].statu[k];
                __int64 sum = biao[now].cnt[k];
                __int64 numj = ( st % digit[j+1] ) / digit[j];
                __int64 numj_1 = ( st % digit[j+2] ) / digit[j+1];
          //      __int64 tt = ( st % digit[M+2] ) / digit[M+1];
                __int64 newt;

                if( s[i][j+1] == 'O' || s[i][j+1] == '*' ){

                    if( numj == 0 && numj_1 == 0 ){
                        newt = st + digit[j] * ( 1 - numj ) + digit[j+1] * ( 2 - numj_1 );
                        if( j + 1 < M && s[i+1][j+1] != 'X' && s[i][j+2] != 'X' ) biao[now^1].add( newt, sum );
                        if( s[i][j+1] == '*' )  biao[now^1].add( st, sum );
                    }else if( numj == 0 || numj_1 == 0 ){
                        newt = st + digit[j] * ( 0 - numj ) + digit[j+1] * ( numj + numj_1 - numj_1 );
                        if( j + 1 < M && s[i][j+2] != 'X' ) biao[now^1].add( newt, sum );
                        newt = st + digit[j] * ( numj + numj_1 - numj ) + digit[j+1] * ( 0 - numj_1 );
                        if( s[i+1][j+1] != 'X' ) biao[now^1].add( newt, sum );
                    }else{
                        if( numj == 1 && numj_1 == 1 ){
                            int l = find_r( st, j + 1 );
                            if( l <= M ){
                                newt = st + digit[l] * ( 1 - 2 ) - digit[j] * numj - digit[j+1] * numj_1;
                                biao[now^1].add( newt, sum );
                            }
                        }else if( numj == 2 && numj_1 == 2 ){
                            int l = find_l( st, j );
                            if( l >= 0 ){
                                newt = st + digit[l] * ( 2 - 1 ) - digit[j] * numj - digit[j+1] * numj_1;
                                biao[now^1].add( newt, sum );
                            }
                        }else if( numj == 2 && numj_1 == 1 ){
                            newt = st - digit[j] * numj - digit[j+1] * numj_1;
                            biao[now^1].add( newt, sum );
                        }else{
                           // if( tt == 0 ){
                                newt = st - digit[j] * numj - digit[j+1] * numj_1;
								if( ( i > lasti || ( i == lasti && j + 1 >= lastj ) ) && !newt ){
	                                ans += sum;
								}
                        //    }
                        }
                    }

                }else{
                    if( numj == 0 && numj_1 == 0 ){
                        biao[now^1].add( st, sum );
                    }
                }
            }
        }
    }
    return ans;
}

int main(){
    int T, Case = 1;
    cin >> T;
    while( T-- ){
        scanf( "%d%d", &N, &M );
		memset( s, 0, sizeof( s ) );
        for( int i = 1; i <= N; i++ ){
            scanf( "%s", &s[i][1] );
        }
        printf( "Case %d: %I64d\n", Case++, solve() );
    }
    return 0;
}

/*

100

3 3
**O
O**
*O*

12 12
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO

4 4
XXOO
OOOO
OOOO
OOOO

4 4
OOOO
OOOO
OOOO
OOOO
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值