• ural1519


    https://vjudge.net/problem/URAL-1519

    插头dp。。。

    终于A掉了。。。抄了一个板子。。。

    看那个ccy大神的博客 写的非常好。。。

    讲几个问题:插头就是线穿过格子的边缘 左插头就是竖着的轮廓线左边 右插头就是竖着的轮廓线右边。。。我好想没用到这个概念。。。

    然后就是各种分类讨论。。。

    dp初值:dp[0][0]=1 第0行状态为0的方案数为1 

    这个东西还是抄一下吧。。。

    hash版:仿写的 跑的很快 那个hash不是很懂

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    const int N = 199917, M = 20, lim = 199917;
    int n, m, k, endx, endy;
    int a[M][M], tot[2]; //每种方案的总和//存哈希值 
    ll ans;
    ll Hash[N], state[2][N], sum[2][N], bin[M];
    void hash(ll s, ll delta)
    { //把状态哈希成数值 
        int pos = s % lim;
        while(Hash[pos])
        {
            if(state[k][Hash[pos]] == s)
            {
                sum[k][Hash[pos]] += delta;
                return;
            }
            ++pos;
            if(pos == lim) pos = 0;
        }
        ++tot[k];
        Hash[pos] = tot[k];
        state[k][tot[k]] = s; sum[k][tot[k]] = delta;
    }
    void solve()
    {
        tot[0] = sum[0][1] = 1;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
    //            printf("i=%d j=%d
    ", i, j);
                k ^= 1;
                memset(Hash, 0, sizeof(Hash));
                memset(sum[k], 0, sizeof(sum[k]));
                memset(state[k], 0, sizeof(state[k]));
                tot[k] = 0;
                for(int t = 1; t <= tot[k ^ 1]; ++t)
                {        
                    ll s = state[k ^ 1][t];
                    int p = (s >> bin[j - 1]) % 4;
                    int q = (s >> bin[j]) % 4;
                    ll delta = sum[k ^ 1][t];
    //                printf("s=%d p=%d q=%d delta=%d
    ", s, p, q, delta);
                    if(!a[i][j])
                    { //障碍物 
                        if(!p && !q) hash(s, delta);
                        continue;
                    }
                    if(!p && !q)
                    {
                        if(a[i][j + 1] && a[i + 1][j])
                        { //能不能伸出插头 
    //                        printf("bin[j]=%d
    ", bin[j]);
                            s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2;  
                            hash(s, delta);
                        }
                        continue;
                    }
                    if(!p && q)
                    { //有一个插头 
                        if(a[i][j + 1])  
                            hash(s, delta);
                        if(a[i + 1][j])
                        {
                            s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]);
                            hash(s, delta);                     
                        }
                        continue;
                    }
                    if(p && !q)
                    {
                        if(a[i + 1][j])
                            hash(s, delta);
                        if(a[i][j + 1])
                        {
                            s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]);
                            hash(s, delta);
                        }
                        continue;
                    }
                    if(p == 1 && q == 1)
                    {
                        int cnt = 1;
                        for(int v = j + 1; v <= m; ++v)
                        {
                            int t = (s >> bin[v]) % 4;
                            if(t == 1) ++cnt;
                            else if(t == 2) --cnt;
                            if(cnt == 0)
                            {
    //                            printf("v1=%d
    ", v);
                                s -= (1 << bin[v]);
                                break;
                            }
                        }
                        s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]);
                        hash(s, delta);
                        continue;
                    }
                    if(p == 2 && q == 2)
                    {
                        int cnt = 1;
                        for(int v = j - 2; v; --v)
                        {
                            int t = (s >> bin[v]) % 4;
                            if(t == 2) ++cnt;
                            else if(t == 1) --cnt;
                            if(cnt == 0)
                            {
    //                            printf("v2=%d
    ", v);
                                s += (1 << bin[v]);
                                break;
                            }
                        }
                        s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]);
                        hash(s, delta);
                        continue;
                    }
                    if(p == 2 && q == 1)
                    {
                        s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]);
                        hash(s, delta);
                        continue;
                    }
                    if(p == 1 && q == 2)
                    {
    //                    printf("delta=%d
    ", delta);
                        if(i == endx && j == endy) 
                            ans += delta;
                        continue;
                    }
                }    
            }
            for(int i = 1; i <= tot[k]; ++i)
                state[k][i] <<= 2;
        }
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i)
        {
             //每个括号用两位表示 
            char s[M]; scanf("%s", s + 1);
            for(int j = 1; j <= m; ++j) 
            {
                a[i][j] = (s[j] == '.');
                if(s[j] == '.')
                {
                    endx = i;
                    endy = j;
                }
            }
        }
        for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1;
        solve();
        printf("%llu
    ", ans); 
        return 0;
    }
    View Code

    set版:set直接hash判重 但是跑的很慢

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll; 
    const int N = 600010, M = 20;
    int n, m, k, endx, endy;
    int a[M][M];
    ll bin[M], st[N]; //每种方案的总和
    map<ll, ll> sum[2];
    set<ll> s[2]; //存哈希值 
    ll ans;
    void hash(ll state, ll delta)
    { //把状态哈希成数值 
        if(s[k].count(state))
        {
            sum[k][state] += delta;
            return;
        }
        s[k].insert(state);
        sum[k][state] = delta;
    }
    void solve()
    {
        sum[0][0] = 1;
        s[0].insert(0);
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
    //            printf("i=%d j=%d
    ", i, j);
                k ^= 1;
                sum[k].clear();
                s[k].clear();
                for(set<ll>::iterator it = s[k ^ 1].begin(); it != s[k ^ 1].end(); ++it)
                {        
                    ll s = *it;
                    int p = (s >> bin[j - 1]) & 3;
                    int q = (s >> bin[j]) & 3;
                    ll delta;
                    if(j == 1) delta = sum[k ^ 1][*it >> 2];
                    else delta = sum[k ^ 1][*it];
    //                printf("s=%d p=%d q=%d delta=%d
    ", s, p, q, delta);
                    if(!a[i][j])
                    { //障碍物 
                        if(!p && !q) hash(s, delta);
                        continue;
                    }
                    if(!p && !q)
                    {
                        if(a[i][j + 1] && a[i + 1][j])
                        { //能不能伸出插头 
                            s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2;  
                            hash(s, delta);
                        }
                        continue;
                    }
                    if(!p && q)
                    { //有一个插头 
                        if(a[i][j + 1])  
                            hash(s, delta);
                        if(a[i + 1][j])
                        {
                            s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]);
                            hash(s, delta);                     
                        }
                        continue;
                    }
                    if(p && !q)
                    {
                        if(a[i + 1][j])
                            hash(s, delta);
                        if(a[i][j + 1])
                        {
                            s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]);
                            hash(s, delta);
                        }
                        continue;
                    }
                    if(p == 1 && q == 1)
                    {
                        int cnt = 1;
                        for(int v = j + 1; v <= m; ++v)
                        {
                            int t = (s >> bin[v]) & 3;
                            if(t == 1) ++cnt;
                            else if(t == 2) --cnt;
                            if(cnt == 0)
                            {
                                s -= (1 << bin[v]);
                                break;
                            }                        
                        }
                        s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]);
                        hash(s, delta);
                        continue;
                    }
                    if(p == 2 && q == 2)
                    {
                        int cnt = 1;
                        for(int v = j - 2; v; --v)
                        {
                            int t = (s >> bin[v]) & 3;
                            if(t == 2) ++cnt;
                            else if(t == 1) --cnt;
                            if(cnt == 0)
                            {
                                s += 1 << bin[v];
                                break;
                            }        
                        }
                        s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]);
                        hash(s, delta);    
                        continue;
                    }
                    if(p == 2 && q == 1)
                    {
                        s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]);
                        hash(s, delta);
                        continue;
                    }
                    if(p == 1 && q == 2)
                    {
                        if(i == endx && j == endy) 
                            ans += delta;
                        continue;
                    }
                }    
            }
            int top = 0;
            for(set<ll>::iterator it = s[k].begin(); it != s[k].end(); ++it)
                st[++top] = ((*it) << 2);
            s[k].clear();
            while(top)
            {
                s[k].insert(st[top]);
                --top;    
            }
        }
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i)
        {
            //每个括号用两位表示 
            char s[M]; scanf("%s", s + 1);
            for(int j = 1; j <= m; ++j) 
            {
                a[i][j] = (s[j] == '.');
                if(s[j] == '.')
                {
                    endx = i;
                    endy = j;
                }
            }
        }
        for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1;
        solve();
        printf("%llu
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    luogu1196 银河英雄传说 (并查集)
    [BZOJ2243][SDOI2011]染色
    [BZOJ1879] [Sdoi2009]Bill的挑战
    [Noip2003] 侦探推理
    [Noip2005] 篝火晚会
    [JZOJ100047] 【NOIP2017提高A组模拟7.14】基因变异
    [九省联考2018]一双木棋chess
    [Noip2009] 靶形数独
    [Luogu2737] [USACO4.1]麦香牛块Beef McNuggets
    [BZOJ3109] [cqoi2013]新数独
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6947490.html
Copyright © 2020-2023  润新知