poj 2778 DNA Sequence AC自动机+矩阵快速幂

本文探讨了如何使用矩阵快速幂算法解决大规模DNA序列分析问题,避免了传统动态规划方法的局限性,适用于长达2e9的DNA序列。通过构建自动机状态转移矩阵并进行快速幂运算,高效计算不包含特定疾病片段的DNA序列数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DNA Sequence

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 19923 Accepted: 7585

Description

It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments. 

Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n. 

Input

First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences. 

Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10. 

Output

An integer, the number of DNA sequences, mod 100000.

Sample Input

4 3
AT
AC
AG
AA

Sample Output

36

题意:给出m个DNA序列,问有多少个一个长为n且不包含以上序列的DNA序列

n的长度为2e9,普通的dp是不行的,所以需要将dp的递推转为矩阵乘法然后快速幂。

矩阵元素c[i][j]表示从自动机状态i到状态j的方案个数,那么长为n只需要乘n次。类似hdu2157的构建方式。

 

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define ll long long
const int mod = 100000;
const int maxm = 125;
int n;
int tr[maxm][5], fail[maxm], last[maxm], cnt, id[maxm];
char str[maxm];
struct node
{
	ll c[maxm][maxm];
}f;
void init()
{
	memset(last, 0, sizeof(last));
	memset(tr, 0, sizeof(tr));
	memset(fail, 0, sizeof(fail));
	cnt = 0;
}
node multi(node a, node b)
{
	node x = { 0 };
	for (int i = 0;i <= cnt;i++)
	{
		for (int j = 0;j <= cnt;j++)
		{
			for (int k = 0;k <= cnt;k++)
			{
				x.c[i][j] += (a.c[i][k] * b.c[k][j]);
				x.c[i][j] %= mod;
			}
		}
	}
	return x;
}
node ksm(node rev, int k)
{
	node x = { 0 };
	for (int i = 0;i <= cnt;i++)
		x.c[i][i] = 1;
	while (k)
	{
		if (k % 2 == 1)
			x = multi(x, rev);
		rev = multi(rev, rev);
		k /= 2;
	}
	return x;
}
void insert()
{
	int len = strlen(str);
	int now = 0;
	for (int i = 0;i < len;i++)
	{
		int num = id[str[i]];
		if (!tr[now][num])
			tr[now][num] = ++cnt;
		now = tr[now][num];
	}
	last[now] = 1;
}
void find_fail()
{
	int now;
	queue<int>q;
	for (int i = 0;i < 4;i++)
		if (tr[0][i]) q.push(tr[0][i]);
	while (!q.empty())
	{
		now = q.front();q.pop();
		for (int i = 0;i < 4;i++)
		{
			if (tr[now][i])
			{
				fail[tr[now][i]] = tr[fail[now]][i];
				q.push(tr[now][i]);
			}
			else tr[now][i] = tr[fail[now]][i];
			if (last[tr[fail[now]][i]]) last[tr[now][i]] = 1;
		}
	}
}
void work()
{
	node rev = { 0 };
	for (int i = 0;i <= cnt;i++)
	{
		if (last[i]) continue;
		for (int j = 0;j < 4;j++)
		{
			if (!last[tr[i][j]])
				rev.c[i][tr[i][j]]++;
		}
	}
	rev = ksm(rev, n);
	ll ans = 0;
	for (int i = 0;i <= cnt;i++)
		ans = (ans + rev.c[0][i]) % mod;
	printf("%lld\n", ans);
}
int main()
{
	int i, j, k, sum, m;
	id['A'] = 0, id['C'] = 1;
	id['T'] = 2, id['G'] = 3;
	while (scanf("%d%d", &m, &n) != EOF)
	{
		init();
		for (i = 1;i <= m;i++)
		{
			scanf("%s", str);
			insert();
		}
		find_fail();
		work();
	}
	return 0;
}

 

内容概要:本文针对火电厂参与直购交易挤占风电上网空间的问题,提出了一种风火打捆参与大用户直购交易的新模式。通过分析可再生能源配额机制下的双边博弈关系,建立了基于动态非合作博弈理论的博弈模型,以直购电价和直购电量为决策变量,实现双方收益均衡最大化。论文论证了纳什均衡的存在性,并提出了基于纳什谈判法的风-火利益分配方法。算例结果表明,该模式能够增加各方收益、促进风电消纳并提高电网灵活性。文中详细介绍了模型构建、成本计算和博弈均衡的实现过程,并通过Python代码复现了模型,包括参数定义、收益函数、纳什均衡求解、利益分配及可视化分析等功能。 适合人群:电力系统研究人员、能源政策制定者、从事电力市场交易的工程师和分析师。 使用场景及目标:①帮助理解风火打捆参与大用户直购交易的博弈机制;②为电力市场设计提供理论依据和技术支持;③评估不同政策(如可再生能源配额)对电力市场的影响;④通过代码实现和可视化工具辅助教学和研究。 其他说明:该研究不仅提供了理论分析,还通过详细的代码实现和算例验证了模型的有效性,为实际应用提供了参考。此外,论文还探讨了不同场景下的敏感性分析,如证书价格、风电比例等对市场结果的影响,进一步丰富了研究内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值