L - Lost's revenge HDU - 3341 (AC自动机 + 记忆化搜索 + 变进制算法)

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

题意:把给定的文本串重排,使得每个模式串在文本串中出现的次数和最大。串与串之间可重叠。

思路:很明显要AC自动机处理模式串,然后由于每个字符的数量是固定的,所以要记忆化搜索,但是正常开数组的话,数组的大小为500 * 40 * 40 * 40,显然会 MLE,所以采用变进制法代表每个状态,设num0, num1, num2, num3 为字符 A, T, C, G的数量, c0, c1, c2, c3为当前状态字符A, T, C, G 的数量,那么状态state = c0 * (num1 + 1) * (num2 + 1) * (num3 + 1) + c1 * (num2 + 1) * (num3 + 1) + c2 * (num3 + 1) + c3;

注意:题目没说模式串各不相同,所以插入的时候要Exits[p]++ 而不是 Exits[p] = 1;

#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
using namespace std;
const int maxn = 550;
const int mod = 20090717;
int INF = 1e9;
int nex[maxn][4], Exits[maxn], fail[maxn], last[maxn], cnt;
int num0, num1, num2, num3;
char t[maxn];
int n, m;
int getId(char ch){
	if(ch == 'A') return 0;
	else if(ch == 'T') return 1;
	else if(ch == 'C') return 2;
	else return 3;
}
void insert(char *s, int len){
	int p = 0;
	for(int i = 0; i < len; i++){
		int x = getId(s[i]);
		if(nex[p][x] == 0){
			memset(nex[cnt], 0, sizeof(nex[cnt]));
			Exits[cnt] = 0;
			last[cnt] = 0;
			fail[cnt] = 0;
			nex[p][x] = cnt++;
		}
		p = nex[p][x];
	}
	Exits[p]++;
} 

queue<int> que;
void Build(){
	for(int i = 0; i < 4; i++){
		if(nex[0][i]) que.push(nex[0][i]);
	}
	while(que.size()){
		int p = que.front();
		que.pop();
		Exits[p] += Exits[fail[p]];
		for(int i = 0; i < 4; i++){
			int u = nex[p][i];
			if(u){
				fail[u] = nex[fail[p]][i];
				last[u] = Exits[fail[u]] ? fail[u] : last[fail[u]];
				que.push(u);
			} else {
				nex[p][i] = nex[fail[p]][i];
			}
		}
	}
}

int getState(int c0, int c1, int c2, int c3){
	return c0 * (num1 + 1) * (num2 + 1) * (num3 + 1) + c1 * (num2 + 1) * (num3 + 1) + c2 * (num3 + 1) + c3;
}
int dp[505][15005];
int dfs(int st, int c0, int c1, int c2, int c3){
	int state = getState(c0, c1, c2, c3);
	if(dp[st][state] != -1) return dp[st][state];
	int ans = 0;
	if(c0){
		int u = nex[st][0];
		ans = max(ans, dfs(u, c0 - 1, c1, c2, c3) + Exits[u]);
	}
	if(c1){
		int u = nex[st][1];
		ans = max(ans, dfs(u, c0, c1 - 1, c2, c3) + Exits[u]);
	}
	if(c2){
		int u = nex[st][2];
		ans = max(ans, dfs(u, c0, c1, c2 - 1, c3) + Exits[u]);
	}
	if(c3){
		int u = nex[st][3];
		ans = max(ans, dfs(u, c0, c1, c2, c3 - 1) + Exits[u]);
	}
	dp[st][state] = ans;
	return ans;
}
int main(int argc, char const *argv[])
{
	int ca = 0;
	while(1){
		scanf("%d", &n);
		if(n == 0) break;
		cnt = 1;
		memset(nex[0], 0, sizeof(nex[0]));
		num0 = num1 = num2 = num3 = 0;
		for(int i = 1; i <= n; i++){
			char s[25];
			scanf("%s", s);
			insert(s, strlen(s));
		}
		scanf("%s", t);
		int len = strlen(t);
		for(int i = 0; i < len; i++){
			if(getId(t[i]) == 0) num0++;
			else if(getId(t[i]) == 1) num1++;
			else if(getId(t[i]) == 2) num2++;
			else num3++;
		}
		Build();
		memset(dp, -1, sizeof(dp));
		int ans = dfs(0, num0, num1, num2, num3);
		printf("Case %d: %d\n", ++ca, ans);
	}

    return 0;
}


posted @ 2020-07-07 12:40  从小学  阅读(132)  评论(0编辑  收藏  举报