hdu3341Lost's revenge (AC自动机+变进制dp)

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 3657    Accepted Submission(s): 987


Problem 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 talent in the field of number theory. So Lost had never won the game. He was so ashamed and angry, but he didn't know how to improve his level of number theory.

One noon, when Lost was lying on the bed, the Spring Brother poster on the wall(Lost is a believer of Spring Brother) said hello to him! Spring Brother said, "I'm Spring Brother, and I saw AekdyCoin shames you again and again. I can't bear my believers were being bullied. Now, I give you a chance to rearrange your gene sequences to defeat AekdyCoin!".

It's soooo crazy and unbelievable to rearrange the gene sequences, but Lost has no choice. He knows some genes called "number theory gene" will affect one "level of number theory". And two of the same kind of gene in different position in the gene sequences will affect two "level of number theory", even though they overlap each other. There is nothing but revenge in his mind. So he needs you help to calculate the most "level of number theory" after rearrangement.
 

Input
There are less than 30 testcases.
For each testcase, first line is number of "number theory gene" N(1<=N<=50). N=0 denotes the end of the input file.
Next N lines means the "number theory gene", and the length of every "number theory gene" is no more than 10.
The last line is Lost's gene sequences, its length is also less or equal 40.
All genes and gene sequences are only contains capital letter ACGT.
 

Output
For each testcase, output the case number(start with 1) and the most "level of number theory" with format like the sample output.
 

Sample Input
3 AC CG GT CGAT 1 AA AAA 0
 

Sample Output
Case 1: 3 Case 2: 2
 
题意:给你n个模板串,每个字符串的价值为1,给你一个长度不大于40的字符串,让你重新排列字符串中的字符顺序,使得排序后字符串的总价值最大。
思路:首先容易想到统计字符串中'A','C','T','G'的个数,分别为t0,t1,t2,t3,然后用dp[i][num0][num1][num2][num3]表示当前节点为i,'A'用了num0个,'C'用了num1个,'T'用了num2个,‘G’用了num3个的最大价值。但是这样表示空间复杂度为500*40^4太大了,这样的状态表示不可行。然后我们发现其实ATCG的总个数和为40,总状态数并没有40^4那么多,所以我们采用变进制法,即用state=num0*(t1+1)*(t2+1)*(t3+1)+num1*(t2+1)*(t3+1)+num2*(t3+1)+num3表示ATCG的个数的状态,那么总的状态最大为500*11^4是可以接受的。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 99999999
#define pi acos(-1.0)
#define maxnode 500000
int t0,t1,t2,t3;
char s[14],str[50];
int cas=0;
int dp[505][15005];

struct trie{
    int sz,root,val[maxnode],next[maxnode][4],fail[maxnode];
    int q[1111111];
    void init(){
        int i;
        sz=root=0;
        val[0]=0;
        for(i=0;i<4;i++){
            next[root][i]=-1;
        }
    }
    int idx(char c){
        if(c=='A')return 0;
        if(c=='C')return 1;
        if(c=='T')return 2;
        if(c=='G')return 3;
    }
    void charu(char *s){
        int i,j,u=0;
        int len=strlen(s);
        for(i=0;i<len;i++){
            int c=idx(s[i]);
            if(next[u][c]==-1){
                sz++;
                val[sz]=0;
                next[u][c]=sz;
                u=next[u][c];
                for(j=0;j<4;j++){
                    next[u][j]=-1;
                }
            }
            else{
                u=next[u][c];

            }

        }
        val[u]++;
    }

    void build(){
        int i,j;
        int front,rear;
        front=1;rear=0;
        for(i=0;i<4;i++){
            if(next[root][i]==-1 ){
                next[root][i]=root;
            }
            else{
                fail[next[root][i] ]=root;
                rear++;
                q[rear]=next[root][i];
            }
        }
        while(front<=rear){
            int x=q[front];
            val[x]+=val[fail[x] ];
            front++;
            for(i=0;i<4;i++){
                if(next[x][i]==-1){
                    next[x][i]=next[fail[x] ][i];

                }
                else{
                    fail[next[x][i] ]=next[fail[x] ][i];
                    rear++;
                    q[rear]=next[x][i];
                }
            }
        }
    }
    void chazhao(){
        int i,j;
        int bit[4],num0,num1,num2,num3,state,state1;
        for(i=0;i<=sz;i++){
            for(j=0;j<=15000;j++){
                dp[i][j]=-1;
            }
        }
        dp[0][0]=0;
        bit[0]=(t1+1)*(t2+1)*(t3+1);
        bit[1]=(t2+1)*(t3+1);
        bit[2]=t3+1;
        bit[3]=1;

        for(num0=0;num0<=t0;num0++){
            for(num1=0;num1<=t1;num1++){
                for(num2=0;num2<=t2;num2++){
                    for(num3=0;num3<=t3;num3++){
                        state=bit[0]*num0+bit[1]*num1+bit[2]*num2+bit[3]*num3;
                        for(i=0;i<=sz;i++){
                            if(dp[i][state]==-1)continue;
                            if(num0<t0){
                                state1=state+bit[0];
                                dp[next[i][0] ][state1]=max(dp[next[i][0] ][state1],dp[i][state]+val[next[i][0] ] );
                            }
                            if(num1<t1){
                                state1=state+bit[1];
                                dp[next[i][1] ][state1]=max(dp[next[i][1] ][state1],dp[i][state]+val[next[i][1] ] );
                            }
                            if(num2<t2){
                                state1=state+bit[2];
                                dp[next[i][2] ][state1]=max(dp[next[i][2] ][state1],dp[i][state]+val[next[i][2] ] );
                            }
                            if(num3<t3){
                                state1=state+bit[3];
                                dp[next[i][3] ][state1]=max(dp[next[i][3] ][state1],dp[i][state]+val[next[i][3] ] );
                            }
                        }
                    }
                }
            }
        }
        int maxx=0;
        state=t0*bit[0]+t1*bit[1]+t2*bit[2]+t3*bit[3];
        for(i=0;i<=sz;i++){
            maxx=max(maxx,dp[i][state]);
        }
        printf("Case %d: %d
",++cas,maxx);
    }
}ac;


int main()
{
    int n,m,i,j;
    while(scanf("%d",&n)!=EOF && n!=0){
        ac.init();
        for(i=1;i<=n;i++){
            scanf("%s",s);
            ac.charu(s);
        }
        ac.build();
        scanf("%s",str);
        t0=t1=t2=t3=0;
        int len=strlen(str);
        for(i=0;i<len;i++){
            if(str[i]=='A')t0++;
            else if(str[i]=='C')t1++;
            else if(str[i]=='T')t2++;
            else t3++;
        }
        ac.chazhao();
    }
    return 0;
}


原文地址:https://www.cnblogs.com/herumw/p/9464560.html