hdu 3341 Lost's revenge(AC自动机+变进制状压DP)

题目链接:hdu 3341 Lost‘s revenge

题目大意:给定一些需要匹配的串,然后在给定一个目标串,现在可以通过交换目标串中任意两个位置的字符,要求最

后生成的串匹配尽量多的匹配串,可以重复匹配。

解题思路:这题很明显是AC自动机+DP,但是dp的状态需要开40?40?40?40(记录每种字符的个数),空间承受

不了,但是其实因为目标串的长度有限,为40;所以状态更本不需要那么多,最多只有10?10?10?10,但是通过

40进制的hash转换肯定是不行,可以根据目标串中4种字符的个数,来调整每个位的进制。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

typedef pair<int,int> pii;
const int maxn = 505;
const int maxs = 11 * 11 * 11 * 11;
const int sigma_size = 4;

struct Aho_Corasick {
    int sz, g[maxn][sigma_size];
    int tag[maxn], fail[maxn], last[maxn];

    int c[4], bit[4], dp[maxs][maxn];

    void init();
    int idx(char ch);
    void insert(char* str, int k);
    void getFail();
    void match(char* str);
    void put(int x, int y);
    int solve(char* w);
    int hash(int a, int b, int c, int d);
}AC;

int N;
char w[50];

int main () {
    int cas = 1;
    while (scanf("%d", &N) == 1 && N) {
        AC.init();
        for (int i = 1; i <= N; i++) {
            scanf("%s", w);
            AC.insert(w, i);
        }
        scanf("%s", w);
        printf("Case %d: %d\n", cas++, AC.solve(w));
    }
    return 0;
}

int Aho_Corasick::hash(int a, int b, int c, int d) {
    return a * bit[0] + b * bit[1] + c * bit[2] + d;
}

int Aho_Corasick::solve(char* w) {
    getFail();

    int n = strlen(w);
    memset(c, 0, sizeof(c));
    for (int i = 0; i < n; i++)
        c[idx(w[i])]++;
    for (int i = 0; i < 4; i++) {
        bit[i] = 1;
        for (int j = i + 1; j < 4; j++)
            bit[i] *= (c[j]+1);
    }

    int ans = 0, t[4];
    memset(dp, -1, sizeof(dp));
    dp[hash(c[0], c[1], c[2], c[3])][0] = 0;

    for (t[0] = c[0]; t[0] >= 0; t[0]--)
        for (t[1] = c[1]; t[1] >= 0; t[1]--)
            for (t[2] = c[2]; t[2] >= 0; t[2]--)
                for (t[3] = c[3]; t[3] >= 0; t[3]--) {
                    int s = hash(t[0], t[1], t[2], t[3]);
                    for (int i = 0; i < 4; i++) {
                        if (t[i] == 0)
                            continue;
                        int ss = s - bit[i];

                        for (int k = 0; k < sz; k++) {

                            if (dp[s][k] < 0)
                                continue;

                            int u = k;
                            while (u && g[u][i] == 0)
                                u = fail[u];
                            u = g[u][i];

                            if (dp[ss][u] < dp[s][k] + tag[u]) {
                                dp[ss][u] = dp[s][k] + tag[u];
                                ans = max(ans, dp[ss][u]);
                            }
                        }
                    }
                }

    return ans;
}

void Aho_Corasick::init() {
    sz = 1;
    tag[0] = 0;
    memset(g[0], 0, sizeof(g[0]));
}

int Aho_Corasick::idx(char ch) {
    if (ch == ‘A‘)
        return 0;
    if (ch == ‘C‘)
        return 1;
    if (ch == ‘G‘)
        return 2;
    return 3;
}

void Aho_Corasick::put(int x, int y) {
}

void Aho_Corasick::insert(char* str, int k) {
    int u = 0, n = strlen(str);

    for (int i = 0; i < n; i++) {
        int v = idx(str[i]);
        if (g[u][v] == 0) {
            tag[sz] = 0;
            memset(g[sz], 0, sizeof(g[sz]));
            g[u][v] = sz++;
        }
        u = g[u][v];
    }
    tag[u]++;
}

void Aho_Corasick::match(char* str) {
    int n = strlen(str), u = 0;
    for (int i = 0; i < n; i++) {
        int v = idx(str[i]);
        while (u && g[u][v] == 0)
            u = fail[u];

        u = g[u][v];

        if (tag[u])
            put(i, u);
        else if (last[u])
            put(i, last[u]);
    }
}

void Aho_Corasick::getFail() {
    queue<int> que;

    for (int i  = 0; i < sigma_size; i++) {
        int u = g[0][i];
        if (u) {
            fail[u] = last[u] = 0;
            que.push(u);
        }
    }

    while (!que.empty()) {
        int r = que.front();
        que.pop();

        for (int i = 0; i < sigma_size; i++) {
            int u = g[r][i];

            if (u == 0) {
                g[r][i] = g[fail[r]][i];
                continue;
            }

            que.push(u);
            int v = fail[r];
            while (v && g[v][i] == 0)
                v = fail[v];

            fail[u] = g[v][i];
            tag[u] += tag[fail[u]];
            //last[u] = tag[fail[u]] ? fail[u] : last[fail[u]];
        }
    }
}

hdu 3341 Lost's revenge(AC自动机+变进制状压DP)

时间: 2024-10-23 20:59:02

hdu 3341 Lost's revenge(AC自动机+变进制状压DP)的相关文章

HDU 3341 Lost&#39;s revenge AC自动机+dp

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3757    Accepted Submission(s): 1020 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

Hdu 3341 Lost&#39;s revenge (ac自动机+dp+hash)

题目大意: 给出很多个DNA串,每一个串的价值为1,最后给出一个长串,要你重新排列最后的串使之它所有的子串的权值和最大. 思路分析: 最先容易想到的思路就是搜!管她3721..直接一个字符一个字符的码,然后在AC自动机上判断最后的权值.TLE哟. 然后发现搜过不去,那就dp咯.再容易想到的就是dp[i][a][b][c][d] 表示此时遍历AC自动机的节点在i,然后构成了a个A,b个G,c个C,d个T的权值. 再一看内存,500*40*40*40*40...然后...就没有然后了 再想,因为它说

HDU 3341 Lost&#39;s revenge AC自动机+ 状态压缩DP

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串 解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配.我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一

HDU 3001 Travelling 3进制状压dp

题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <vector> #include <string> #include <cmath

HDU 4539郑厂长系列故事――排兵布阵(状压DP)

HDU 4539  郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 1 //#pragma comment(linker,"/STACK:102400000,102400000") 2 #include <map> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #i

[HDU 4787] GRE Words Revenge (AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自动机- -然后暴力查找.. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #include <map> 6 #include

hdu 3001 Travelling TSP变形 三进制状压dp

// hdu 3001 TSP问题的变形 // 这次到每个点最多两次,所以可以用三进制的类推 // dp[S][u]表示当前在u点访问状态为S时所得到的最小的开销 // 采用刷表法,即用当前的状态推出它所能转移的状态 // dp[S][u] 可以到达的状态为dp[S+state[v]][v](dist[u][v]!=inf) // dp[S+state[v]][v] = max(dp[S+state[v]][v],dp[S][u]+dist[u][v]); // 其中每个点最多访问2次 // 技

HDU 3001 三进制状压DP

N个城市,M条道路,每条道路有其经过的代价,每一个城市最多能够到达两次,求走全然部城市最小代价,起点随意. 三进制状压.存储每一个状态下每一个城市经过的次数. 转移方程: dp[i+b[k]][k]=Min(dp[i+b[k]][k],dp[i][j]+dis[j][k]); #include "stdio.h" #include "string.h" const int inf=0x3f3f3f3f; int b[15],mark[60010][15],dp[60

HDU 3001 三进制 状压dp

Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3789    Accepted Submission(s): 1182 Problem Description After coding so many days,Mr Acmer wants to have a good rest.So travelling is