2020年第十八届西电程序设计竞赛网络预选赛之Problem C 没人比我更懂 COVID-19

题目描述
现在,一种高度危险的病毒袭击了学园都市,人们陷入危难之中。
作为蓝星上最无所不知的人,你对病毒基因了如指掌。为了拯救即将废弃的
校赛,行星防御理事会找到了你。
现在你必须找出病毒所有可能的变异情况,以抵御病毒的攻击。
给定 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)/~

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值