[TJOI2018] 碱基序列(题库给的什么鬼名字)

题目描述
小豆参加了生物实验室。在实验室里,他主要研究蛋臼质。他现在研究的蛋臼质是由k个氨基酸按一定顺序构成的 。每一个氨基酸都可能有a种碱基序 列si_j 构成。现在小豆有一个碱基串s,小豆想知道在这个碱基上都多少中 不同的组合方式可能得到这个蛋白质。即求由k段字符串有序合并成的字符串s1,有多少种不同方式能够匹配字符串 s,其中k段字符串的选法不同,或者与s匹配上 的位置不同认为是不同的方式。

输入格式
第一行一个数,表示这个蛋臼质由k个氨基酸。 第二行一个字符串s,表示小豆现在有的碱基串。 第三行开始接下来k行表示第i个氨基酸可能的碱基序列,对于第i个氨基酸,ai表示这个氨基酸可能的碱基序列种数, 接下来ai个字符串表示这ai 种可能的碱基序列,用空格隔开。 1 ≤ k ≤ 100, |s| ≤ 10000,ai ≤ 10

输出格式
输出一个数目表示不同的方案数 (不同的方案数是指不同的子碱基串或者相同的碱基串不同的氨基酸排列方式) 答案对1e9+7取模

样例
样例输入
2
ABC
2 A AB
2 C BC
样例输出
2

我他妈就是弱智
image

感谢wlesq的题解
这是一道hash+背包DP(很显然我没发现),如果当前选出的子串可以匹配,就可以从字符串相对应的子串的前一位置的状态转移过来(注意,我说的是子串第一位的前一位),不懂的看下图
image
f[r-len+1]是没有数的,f[r]的上一个状态是f[r-len],这也解释了为什么初始化f要从0开始,因为可能减完后的下标会变成0
f[i][j]表示前i长的主串匹配了第j列的碱基的情况
f[i][j]+=f[ilenj,k][j1](hash(s1)==hash(sj,k))
然后没了,关于前缀求子串可以看乌力波谴责wlesq速速修改题解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int base=131;
const int mod=1e9+7;
int n,m;
char s[12000];
char c[120][15][1000];
long long f[12000][120];
ull has[12000];
int num[120];
ull bas[12000];
void get(){
	int len=strlen(s+1);
	for(int i=1;i<=len;i++){
		has[i]=has[i-1]*base+s[i];
	}
	bas[0]=1;
	for(int i=1;i<=len;i++){
		bas[i]=bas[i-1]*base;
	}
}
ull gethash(int from,int to){
	return has[to]-has[from-1]*bas[to-from+1];
}
ull check(char si[]){
	ull res=0;
	int len=strlen(si+1);
	for(int i=1;i<=len;i++){
		res=res*base+si[i];
	}
	return res;
}
int main(){
	cin>>n;
	scanf("%s",s+1);
	for(int i=1;i<=n;i++){
		cin>>m;
		num[i]=m;
		for(int j=1;j<=m;j++){
			scanf("%s",c[i][j]+1);
		}
	}
	get();
	int lensum=strlen(s+1);
	for(int i=0;i<=lensum;i++) f[i][0]=1;
	for(int i=1;i<=n;i++){
		for(int k=1;k<=num[i];k++){
			int len2=strlen(c[i][k]+1);
//			for(int j=1;j<=len2;j++){
//				cout<<c[i][k][j];
//			} 
			for(int j=lensum;j>=len2;j--){
				if(check(c[i][k])==gethash(j-len2+1,j)){
					f[j][i]=(f[j][i]+f[j-len2][i-1])%mod;
//					cout<<f[j][i]<<" "<<f[j-len2][i-1]<<" ";
				}
			}
//			cout<<endl;
		}
	}
	long long ans=0;
	for(int i=1;i<=lensum;i++){
		ans=(ans+f[i][n])%mod;
	}
	cout<<ans%mod<<endl;
}

对了,我用vector+string没调出来,有大佬能否看一下

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef signed long long ull;
vector<string> q[120];
ull has[12000],bas[12000];
long long f[12000][120];
const int base=131,mod=1e9+7;
int n,m;
string s,c;
void solve(){
	bas[0]=1;
	has[0]=s[0];
	for(int i=1;i<s.length();i++){
		has[i]=has[i-1]*base+s[i];
	}
	for(int i=1;i<=10000;i++) bas[i]=bas[i-1]*base;
}
long long check(string lm){
	ull res=0;
	for(int i=0;i<lm.length();i++){
		res=res*base+lm[i];
	}
	return res;
}
long long find(int from,int to){
	if(from<=0) return has[to];
	return (has[to]-has[from-1]*bas[to-from+1]);
}
int main(){
	cin>>n;
	cin>>s;
	solve();
	for(int i=1;i<=n;i++){
		cin>>m;
		for(int j=1;j<=m;j++){
			cin>>c;
			q[i].push_back(c);
		}
	}
//	cout<<q[2].size()<<endl;
//	cout<<s.length(); 
	for(int i=0;i<s.length();i++) f[i][0]=1;
	
	for(int i=1;i<=n;i++){
		int len1=q[i].size()-1;
		for(int k=0;k<=len1;k++){
			int len=q[i][k].length();
			int len3=s.length()-1;
			for(int j=len3;j>=len-1;j--){
				if(check(q[i][k])==find(j+1-len,j)){
					if(j-len<=0) f[j][i]+=f[0][i-1];
					else f[j][i]+=f[j-len][i-1];
//					cout<<j<<" "<<i<<" "<<f[j][i]<<" ";
//					cout<<"|||";
				}
			}
		}
//		cout<<endl;
	}
//	cout<<endl;
//	cout<<endl;
	long long ans=0;
//	for(int i=0;i<s.length();i++){
//		for(int j=1;j<=n;j++){
//			cout<<f[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	for(int i=0;i<s.length();i++){
		ans+=f[i][n];
	}
	cout<<ans%mod<<endl;
} 

对了,如果用关于string的函数(例如求长度),最好是用变量储存一下,不然就会出现以下情况
image
注意j的值

posted @   shaoyufei  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示