zoukankan      html  css  js  c++  java
  • L

    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
    ", ++ca, ans);
    	}
    
        return 0;
    }
    
    
    
  • 相关阅读:
    异常处理
    反射4中内置函数
    property装饰器与继承
    封装
    面向对象编程
    面向对象编程
    项目开发规范
    logging模块
    22. 一个题来探查对 字符串,指针,数组三方面的关联使用方面的概念是否清晰,分析下面三个printf打印什么?
    21. 让指针数组结尾带NULL,使遍历时不依靠计算整个数组大小就可以在结尾遍历结束
  • 原文地址:https://www.cnblogs.com/PCCCCC/p/13260113.html
Copyright © 2011-2022 走看看