Lost's revenge - HDU 3341 (自动机+DP)

题目大意:先给你一些子串,然后给你一个母串,母串里面的字母可以任意调换位置,问最多这个母串经过一些位置变动最多能包含多少个子串。

 

分析:可以比较明显的看出来的DP,先求出来ATGC分别有多少,然后再处理,不过有个比较麻烦的地方,因为ATGC的字母数最多是40,因为不知道那种字母所以是40*40*40*40,很明显这种复杂度太高,开始使用了一次打标,把每种状态都保存下来,并且保存它的下一个状态,不过很不幸这种方法TLE了,因为找他的下一个状态不是太容易,看了大神的题解后明白,其实可以使用4种不同的进制来做,进制数就是这个碱基数的总个数,这样复杂度很明显就降低了,而且状态再转移的时候也很容易。

 

代码如下:

===================================================================================================================================

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

const int MAXN = 15007;
const int MaxSon = 4;
const int oo = 1e9;

int Find(char ch)
{
    if(ch == ‘A‘)return 0;
    if(ch == ‘T‘)return 1;
    if(ch == ‘G‘)return 2;

    return 3;
}
struct Ac_Trie
{
    int next[507][4];
    int Fail[507], End[507];
    int root, cnt;

    int newnode()
    {
        for(int i=0; i<MaxSon; i++)
            next[cnt][i] = -1;
        Fail[cnt] = End[cnt] = false;

        return cnt++;
    }
    void InIt()
    {
        cnt = 0;
        root = newnode();
    }
    void Insert(char s[])
    {
        int now = root;

        for(int i=0; s[i]; i++)
        {
            int k = Find(s[i]);

            if(next[now][k] == -1)
                next[now][k] = newnode();
            now = next[now][k];
        }

        End[now] += 1 ;
    }
    void GetFail()
    {
        int now = root;
        queue<int> Q;

        for(int i=0; i<MaxSon; i++)
        {
            if(next[now][i] == -1)
                next[now][i] = root;
            else
            {
                Fail[next[now][i]] = root;
                Q.push(next[now][i]);
            }
        }

        while(Q.size())
        {
            now = Q.front();
            Q.pop();

            for(int i=0; i<MaxSon; i++)
            {
                if(next[now][i] == -1)
                    next[now][i] = next[Fail[now]][i];
                else
                {
                    Fail[next[now][i]] = next[Fail[now]][i];
                    Q.push(next[now][i]);
                }
            }

            End[now] += End[Fail[now]];
        }
    }
};
struct ATGC
{
    int sum[4], bit[4];
    int dp[507][MAXN];
    Ac_Trie ac;

    void GetSum(char s[])
    {
        memset(sum, 0, sizeof(sum));
        memset(bit, 0, sizeof(bit));

        for(int i=0; s[i]; i++)
        {
            int k = Find(s[i]);
            sum[k]++;
        }
    }
    void GetBit()
    {
        bit[0] = (sum[1]+1)*(sum[2]+1)*(sum[3]+1);
        bit[1] = (sum[2]+1)*(sum[3]+1);
        bit[2] = sum[3]+1;
        bit[3] = 1;
    }
    int GetDp()
    {
        memset(dp, -1, sizeof(dp));
        dp[0][0] = 0;

        int ans = 0;

        for(int A=0; A<=sum[0]; A++)
        for(int T=0; T<=sum[1]; T++)
        for(int G=0; G<=sum[2]; G++)
        for(int C=0; C<=sum[3]; C++)
        {
            int k = A*bit[0] + T*bit[1] + G*bit[2] + C*bit[3];

            for(int i=0; i<ac.cnt; i++)
            {
                if(dp[i][k] == -1)continue;

                for(int j=0; j<MaxSon; j++)
                {
                    if(j == 0 && A==sum[0])continue;
                    if(j == 1 && T==sum[1])continue;
                    if(j == 2 && G==sum[2])continue;
                    if(j == 3 && C==sum[3])continue;

                    int next = ac.next[i][j];
                    int nextk = k + bit[j];

                    dp[next][nextk] = max(dp[next][nextk], dp[i][k]+ac.End[next]);
                    ans = max(ans, dp[next][nextk]);
                }
            }
        }

        return ans;
    }
};

ATGC a;

int main()
{
    int i, N, t=1;

    while(scanf("%d", &N), N)
    {
        char s[107];
        a.ac.InIt();

        for(i=0; i<N; i++)
        {
            scanf("%s", s);
            a.ac.Insert(s);
        }
        a.ac.GetFail();

        scanf("%s", s);

        a.GetSum(s);
        a.GetBit();

        int ans = a.GetDp();

        printf("Case %d: %d\n", t++, ans);
    }

    return 0;
}

Lost's revenge - HDU 3341 (自动机+DP)

时间: 2024-10-09 21:15:29

Lost's revenge - HDU 3341 (自动机+DP)的相关文章

Lost&#39;s revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A][B][C][D] 表示在AC自动机 i 这个节点上,用了A个A,B个T,C个C,D个G. 然后我算了一下内存,根本开不下这么大的内存. 看了网上题解,然后用通过状压把,A,B,C,D压缩成一维. 这个状压就是通过进制实现需要实现唯一表示 bit[0] = 1; bit[1] = (num[0]

HDU3341 Lost&#39;s revenge(AC自动机+DP)

题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数论基因数 其中ACGT可以hash成一个整数(a*C*G*T+c*G*T+g*T+T),这样用二维数组就行了,而第二维最多也就11*11*11*11个. 接下来转移依然是我为人人型,我是丢进一个队列,用队列来更新状态的值. 这题果然挺卡常数的,只好手写队列,最后4500msAC,还是差点超时,代码也

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)

题目链接:hdu 3341 Lost's revenge 题目大意:给定一些需要匹配的串,然后在给定一个目标串,现在可以通过交换目标串中任意两个位置的字符,要求最 后生成的串匹配尽量多的匹配串,可以重复匹配. 解题思路:这题很明显是AC自动机+DP,但是dp的状态需要开40?40?40?40(记录每种字符的个数),空间承受 不了,但是其实因为目标串的长度有限,为40:所以状态更本不需要那么多,最多只有10?10?10?10,但是通过 40进制的hash转换肯定是不行,可以根据目标串中4种字符的个

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 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): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

HDU - 3341 Lost&amp;#39;s revenge(AC自己主动机+DP)

Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is the man called "nuclear weapon of FZU,descendant of Jingrun", because of his talen

HDU 3341 Lost&#39;s revenge

Lost's revenge Time Limit: 5000ms Memory Limit: 65535KB This problem will be judged on HDU. Original ID: 334164-bit integer IO format: %I64d      Java class name: Main Lost and AekdyCoin are friends. They always play "number game"(A boring game