AC自动机,用40^4 * 50 * 10的空间进行dp。

最大的难点在于hash。

hash一个数列f,数列中的每一位都有一个上限g,即f[i]<=g[i]。

那么可以将该数列hash为这样一个整数,这个整数的每一个位的进制都不同,第i位的进制是g[i] + 1,即第i位满g[i]+1则可进位。(当然由于g[i]是该位的上限,所以永远不可能进位)

用p[i]表示(g[0]+1)*(g[1]+1)*...*(g[i - 1]+1)。那么最终f被hash的结果是p[0]*f[0]+p[1]*f[1]+...。

#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <cstring>
using namespace std; #define D(x) const int MAX_LEN = ;
const int MAX_N = ;
const int MAX_NODE_NUM = * MAX_N;
const int MAX_CHILD_NUM = ; //1.init() 2.insert() 3.build() 4.query()
struct Trie
{
int next[MAX_NODE_NUM][MAX_CHILD_NUM];
int fail[MAX_NODE_NUM];
int count[MAX_NODE_NUM];
int node_cnt;
bool vis[MAX_NODE_NUM]; //set it to false
int root; void init()
{
node_cnt = ;
root = newnode();
memset(vis, , sizeof(vis));
} int newnode()
{
for (int i = ; i < MAX_CHILD_NUM; i++)
next[node_cnt][i] = -;
count[node_cnt++] = ;
return node_cnt - ;
} int get_id(char a)
{
if (a == 'A')
return ;
if (a == 'C')
return ;
if (a == 'T')
return ;
return ;
} void insert(char buf[])
{
int now = root;
for (int i = ; buf[i]; i++)
{
int id = get_id(buf[i]);
if (next[now][id] == -)
next[now][id] = newnode();
now = next[now][id];
}
count[now]++;
} void build()
{
queue<int>Q;
fail[root] = root;
for (int i = ; i < MAX_CHILD_NUM; i++)
if (next[root][i] == -)
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while (!Q.empty())
{
int now = Q.front();
Q.pop();
for (int i = ; i < MAX_CHILD_NUM; i++)
if (next[now][i] == -)
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
count[next[now][i]] += count[fail[next[now][i]]];
Q.push(next[now][i]);
}
}
} int query(char buf[])
{
int now = root;
int res = ; memset(vis, , sizeof(vis));
for (int i = ; buf[i]; i++)
{
now = next[now][get_id(buf[i])];
int temp = now;
while (temp != root && !vis[temp])
{
res += count[temp];
// optimization: prevent from searching this fail chain again.
//also prevent matching again.
vis[temp] = true;
temp = fail[temp];
}
}
return res;
} void debug()
{
for(int i = ;i < node_cnt;i++)
{
printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],count[i]);
for(int j = ;j < MAX_CHILD_NUM;j++)
printf("%2d",next[i][j]);
printf("]\n");
}
}
}ac; char st[MAX_LEN];
int n;
int num[];
int num2[];
int dp[][]; int myhash(int f[])
{
int ret = ;
for (int i = ; i < ; i++)
{
ret += f[i] * num[i];
}
return ret;
} int work()
{
int temp[] = {};
for (int i = ; st[i]; i++)
{
temp[ac.get_id(st[i])]++;
}
num[] = ;
for (int i = ; i >= ; i--)
{
num[i] = (temp[i + ] + ) * num[i + ];
}
memset(dp, -, sizeof(dp));
int f[];
int g[];
int ret = ;
for (f[] = ; f[] <= temp[]; f[]++)
for (f[] = ; f[] <= temp[]; f[]++)
for (f[] = ; f[] <= temp[]; f[]++)
for (f[] = ; f[] <= temp[]; f[]++)
{
for (int u = ; u < ac.node_cnt; u++)
{
int h = myhash(f);
for (int j = ; j < ; j++)
{
g[j] = f[j];
}
int temp2 = ;
for (int j = ; j < ; j++)
{
g[j]--;
int h2 = myhash(g);
int v = ac.next[u][j];
if (g[j] >= )
{
temp2 = max(temp2, dp[h2][v]);
D(printf("\t\t\t%d %d %d %d %d %d %d\n", g[], g[], g[], g[], v, temp2, h2));
}
g[j]++;
}
dp[h][u] = temp2 + ac.count[u];
ret = max(ret, dp[h][u]);
D(printf("%d %d %d %d %d %d %d\n", f[], f[], f[], f[], u, dp[h][u], h));
}
}
return dp[myhash(temp)][ac.root];
} int main()
{
int t = ;
while (scanf("%d", &n), n)
{
ac.init();
for (int i = ; i < n; i++)
{
scanf("%s", st);
ac.insert(st);
}
ac.build();
scanf("%s", st);
printf("Case %d: %d\n", ++t, work());
}
return ;
}

poj3341的更多相关文章

随机推荐

  1. Linux下Redis常用命令

    >src/redis-server  启动 Redis 服务  或者>src/redis-server redis.conf src/redis-server redis.conf 1&g ...

  2. 前端入门级之如何从零开始前端(估计要被人鄙视成LOW货了)入门篇

    <!------------------------------------------------------基本说明开始----------------------------------- ...

  3. PHP简单封装MysqlHelper类

    MysqlHelper.class.php 1: <?php 2:  3: /** 4: * Mysql数据帮助类 5: */ 6: class MysqlHelper 7: { 8: func ...

  4. SqlServer中字符串和日期类型的转换

    SQL Server Date 函数 定义和用法 CONVERT() 函数是把日期转换为新数据类型的通用函数. CONVERT() 函数可以用不同的格式显示日期/时间数据. 语法 CONVERT(da ...

  5. ElasticSearch 2 (6) - 插件安装Head、Kopf与Bigdesk

    ElasticSearch 2 (6) - 插件安装Head.Kopf与Bigdesk 摘要 安装Elasticsearch插件Head.Kopf与Bigdesk 版本 elasticsearch版本 ...

  6. (:: operator)作用域限定符的几种使用

    一.(:: operator)解决局部变量与全局变量重名问题 ; int main() { ; cout<<var<<endl;//local variable cout< ...

  7. 网络编程3-URL编程(URL)

    1.URL(Uniform Resource Locatior) 统一资源占位符,表示Intenet上某一资源的地址 2.URL的组成部分 传输协议:主机名:端口号:文件名 例:http://192. ...

  8. SQL Server中解决死锁

    SQL Server中解决死锁的新方法介绍 数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL Server 2005, 现在似乎有了一种新的解决办法. 将下面的 ...

  9. Asp.Net网页头部动态加载标题、描述、关键字、css和js文件的方法

    首先head标签上添加runat="server". protected void Page_Load(object sender, EventArgs e) { Page.Tit ...

  10. CSS Image Sprite--网页图片应用处理方式

    CSS Sprites简介 CSSSprites在国内很多人叫css精 灵,是一种网页图片应用处理方式.它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片 ...