CF 593 A 2Char(选择合适的枚举方式)

题目链接:
CF 593 A 2Char
题意:
给出n个只含小写英文字母的字符串,选择若干字符串,拼成一个最多只含两种字母的最长的字符串,输出最长字符串长度。
分析:
我是选择枚举每个最多只含两种字母字符串,然后遍历其他只含改字符串所拥有字母的字符串,最后在处理下都是单种类字母字符串的拼接,这样写不仅代码冗长,而且也容易出错。
看了别人家的代码,发现可以枚举最终字符串含有的所有可能的字母组合,然后对每种组合遍历所有的字符串,判断每个是不是只含有这种组合。Nice~

CODE:

//15MS 0KB
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstring>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn=110;

int n,ans;
string s[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)
        {
            cin>>s[i];
        }

        ans=0;
        for(int i=0;i<26;i++)//枚举26个字母中的每一个字母
        {
            for(int j=i+1;j<26;j++)//符合条件的最优解一定是两种字符(存在不止一种字符时)
            {
                int tmp=0;
                for(int k=0;k<n;k++)
                {
                    int len=s[k].size();
                    int flag=1;
                    for(int h=0;h<len;h++)
                    {
                        if(s[k][h]!=i+'a'&&s[k][h]!=j+'a')//字符串包含了不止i,j字符
                        {
                            flag=0;
                            break;
                        }
                    }
                    if(flag) tmp+=len;
                }
                ans=max(ans,tmp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
//15MS 100KB
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <climits>
using namespace std;

const int maxn=1010;

int n,cnt,ans;
char s[110][maxn];
int vis[30],flag[110],num[110][3],len[110];

int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    while(~scanf("%d",&n))
    {
        memset(flag,0,sizeof(flag));
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            scanf("%s",s[i]);
            len[i]=strlen(s[i]);
            cnt=0;
            memset(vis,0,sizeof(vis));
            for(int j=0;j<len[i];j++)
            {
                int t=s[i][j]-'a'+1;
                if(!vis[t])
                {
                    vis[t]=1;
                    cnt++;
                    if(cnt>=3) break;
                }
            }
            if(cnt==3) flag[i]=1;//该字符串含有2个以上种类的字符,废弃
            else
            {
                if(cnt==2)
                {
                    num[i][0]=1;//num[i][0]==1表示第i个字符串含有两种字符
                    int tot=0;
                    for(int j=1;j<30;j++)
                        if(vis[j]) num[i][++tot]=j;//用num[i][1]和num[i][2]分别记录这两个字符
                }
                else//cnt=1;//单一字符合并
                {   int t;
                    for(int j=1;j<30;j++)
                        if(vis[j]) t=j;
                    for(int j=0;j<i;j++)//查找已有字符是否有同样的单一字符字符串
                    {
                        if(!flag[j]&&num[j][0]==0&&num[j][1]==t)
                        {
                            len[j]+=len[i];//将已有的同样的单一字符字符串长度增加
                            flag[i]=1;//现在的字符串废弃
                            break;
                        }
                    }
                    if(flag[i]!=1)//未成功合并
                    {
                        num[i][0]=0;//添加新的单一字符串
                        num[i][1]=t;
                    }
                }
            }
        }
        int a,b;
        ans=0;
        for(int i=0;i<n;i++)//枚举每个字符串
        {
            int tmp=0;
            if(flag[i]) continue;//字符串已经废弃了
            tmp=len[i];
            if(num[i][0]==1)//该字符串有两种字符
            {
                a=num[i][1],b=num[i][2];
            }
            else a=num[i][1],b=-1;//只有一种字符
            for(int j=0;j<n;j++)
            {
                if(i==j||flag[j]) continue;
                if(b!=-1)//i字符串含有两个字符
                {
                    if(num[j][0]==0&&(num[j][1]==a||num[j][1]==b)) tmp+=len[j];//j字符串只含有一个字符
                    else if(num[j][0]==1)//j字符串含有两个字符
                    {
                        if(num[j][1]==a&&num[j][2]==b) tmp+=len[j];
                        if(num[j][1]==b&&num[j][2]==a) tmp+=len[j];
                    }
                }
                else//i字符串只含有一种字符
                {
                    if(num[j][0]==0&&num[j][1]==a) tmp+=len[j];
                    //j字符串必须也只含有一种且字符种类相同
                }
            }
            ans=max(ans,tmp);
        }
        //处理选择两个最长单字符串情况
        int max1=0,ind=-1,max2=0;
        for(int i=0;i<n;i++)//选择最长的单字符串
            if(!flag[i]&&num[i][0]==0&&len[i]>max1)
            {
                max1=len[i];
                ind=i;
            }
        for(int i=0;i<n;i++)
            if(!flag[i]&&num[i][0]==0&&len[i]>max2&&i!=ind) max2=len[i];
        //不能用len[i]!=max1来判断重复,因为有可能最长单字符串不止一个
        printf("%d\n",max(max1+max2,ans));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值