题目描述
现在,一种高度危险的病毒袭击了学园都市,人们陷入危难之中。
作为蓝星上最无所不知的人,你对病毒基因了如指掌。为了拯救即将废弃的
校赛,行星防御理事会找到了你。
现在你必须找出病毒所有可能的变异情况,以抵御病毒的攻击。
给定 n 个病毒碱基序列片段,由大写字母 ATCG 表示,长度均为 m。
你发现对于两串碱基序列,它们交叉变异的结果仅取决于对应位置上的碱
基,规律如下:
× A T C G
A A T C G
T T A G C
C C G A T
G G C T A
例如,序列 AACGT 与 TACAG 交叉将得到 TAAGC。
你想知道,选取任意个病毒并按任意顺序交叉,总共能获得多少种不同的序
列。
注意: 每串基因序列最多用一次。
输入
第一行为用空格分隔的两个正整数 n , m 。满足 1 ≤ n ≤ 10 ,1 ≤ m ≤ 20。
然后为 n 行长度为 m 的字符序列,由大写字母 ATCG 构成。
输出
一个整数,表示能组合出多少种不同的序列。
样例
样例输入 样例输出
3 2
AT
TA
GG
7
May 10, 2020 4
2020 年西电程序设计竞赛网络赛
样例解释
除了原来的 AT、TA、GG 三种
还可交叉出
AT×TA=TT
AT×GG=GC
TA×GG=CG
AT×TA×GG=CC
提示
你翻出了之前研究的记录,但残缺的页面上只留下这几个字:
AT-1
TA-4
GG-15
思路:恕我直言,这个题目的提示真的没有发现是怎么回事,可能是我太菜了。我们可以发现字符串相乘是符合交换律的,也就是同样的字符串相乘,无论谁前谁后,都是没关系的。这就转换成了任意个数的字符串相乘,最终会出现多少个组合。我的天,在我想明白这一点之前,我弄的全排列求得所有的组合。后来想过来之后,蓝桥中不是很多这样的题吗,我傻了。。dfs就可以了。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxx=100;
int a[maxx];
char s[100001][maxx*2];
char mp[30][30],s1[24];
set<string> rr,zz;
vector<int> ans;
int n,m,x;
inline void init()
{
mp[0][0]=mp[2][2]=mp[6][6]=mp[19][19]='A';
mp[0][19]=mp[19][0]='T';
mp[0][2]=mp[2][0]='C';
mp[0][6]=mp[6][0]='G';
mp[19][2]=mp[2][19]='G';
mp[19][6]=mp[6][19]='C';
mp[2][6]=mp[6][2]='T';
}
inline void solve(char *s0,char *s2)
{
char s3[21];
for(int i=0;i<m;i++)
s3[i]=mp[s0[i]-'A'][s2[i]-'A'];
s3[m]='\0';
strcpy(s1,s3);
}
inline void fcs()
{
if(ans.size()<=1) return ;
solve(s[ans[0]],s[ans[1]]);
for(int i=2;i<ans.size();i++) solve(s1,s[ans[i]]);
string T="";
for(int i=0;i<m;i++) T+=s1[i];
rr.insert(T);
}
inline void dfs(int x)
{
if(x>n)
{
fcs();
return ;
}
ans.push_back(x);
dfs(x+1);
ans.pop_back();
dfs(x+1);
}
int main()
{
string T="";
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n;i++) a[i]=i;
for(int i=1;i<=n;i++) scanf("%s",s[i]);
ans.clear();
dfs(1);
for(int i=1;i<=n;i++)
{
T="";
for(int j=0;j<m;j++) T+=s[i][j];
rr.insert(T);
}
printf("%d\n",rr.size());
return 0;
}
努力加油a啊,(o)/~