codeforces #307 B. ZgukistringZ(枚举+计数)

题目链接:

卖萌的链接

题目大意:

给出一个字符串A,再给出两个字符串B,C,求A中任意量字符交换后(不限制次数)能够得到的使B,C作为子串不重叠且出现次数最多的串

题目分析:

其实就是对A,B,C进行计数,判断A中的各个字母的个数分别能分给几个B和几个C,枚举B的个数,计算C的个数,然后取最大值即可,记录去最大值情况下B出现的次数和C出现的次数然后先把B,C输出对应次数,然后把剩下的字符输出出去就好了。比较恶心的是,这道题竟然卡常数,真的在卡常数,所以要进行一个小的剪枝,也就是先求出B出现的最大次数,也就是A全部转成B的情况下B的个数,优化效果出奇的好,但并不是证明优化效果,复杂度怎么算都是26*o(n)

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 100007

int num1[50];
int num2[50];
int num3[50];
int num[50];

char s1[MAX];
char s2[MAX];
char s3[MAX];

using namespace std;


void scan ( char s[] )
{
    char ch;
    ch = getchar ();
    int i = 0;
    while ( true )
    {
        if ( ch == ' ' || ch == '\r' || ch == '\n' ) break;
        s[i++] = ch;
        ch = getchar();
    }
    s[i] = 0;
}

void print ( char s[] )
{
    int i = 0;
    while ( s[i] )
        putchar ( s[i++] );
}

int main ( )
{
    //while ( true )
    //{
        scan ( s1 );
        memset ( num1 , 0 , sizeof ( num1 ) );
        memset ( num2 , 0 , sizeof ( num2 ) );
        memset ( num3 , 0 , sizeof ( num3 ) );
        //scanf ( "%s" , s2 );
        scan ( s2 );
        //scanf ( "%s" , s3 );
        scan ( s3 );
        int len = strlen(s1);
        for ( int i = 0 ; i < len ; i++ )
            num1[s1[i]-97]++;
        len = strlen(s2);
        for ( int i = 0 ; i < len ; i++ )
            num2[s2[i]-97]++;
        len = strlen(s3);
        for ( int i = 0 ; i < len ; i++ )
            num3[s3[i]-97]++;
        int ans = 0;
        int sum1 = MAX , sum2 = MAX;
        for ( int i = 0 ; i < 26 ; i++ )
            if ( num2[i] )
                sum1 = min ( sum1 , num1[i]/num2[i] );
        for ( int i = 0 ; i < 26 ; i++ )
            if ( num3[i] )
                sum2 = min ( sum2 , num1[i]/num3[i] );
        int index = sum1;
        sum1 = sum2 = 0;
        for ( int i = 0 ; i <= index ; i++ )
        {
            bool flag = false;
            for ( int j = 0 ; j < 26 ; j++ )
            {
                num[j] = num1[j] - num2[j]*i;
                if ( num[j] < 0 )
                {
                    flag = true;
                    break;
                }

            }
            if ( flag ) continue;
            int temp = MAX;
            for ( int j = 0 ; j < 26 ; j++ )
                if ( num3[j] )
                    temp = min ( temp , num[j]/num3[j] );
            if ( temp + i > ans )
            {
                ans = temp + i;
                sum1 = i;
                sum2 = temp;
            }
        }
        if ( ans = 0 ) print(s1);
        else 
        {
            for ( int i = 0 ; i < sum1 ; i++ )
                //printf ( "%s" , s2 );
                print(s2);
            for ( int i = 0 ; i < sum2 ; i++ )
                //printf ( "%s" , s3 );
                print(s3);
            for ( int i = 0 ; i < 26 ; i++ )
                num1[i] -= sum1*num2[i] + sum2*num3[i];
            for ( int i = 0 ; i < 26 ; i++ )
                while ( num1[i]-- )
                    //printf ( "%c" , 'a'+i );
                    putchar((char)('a'+i));
            puts ("");
        }
    //}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值