Codeforces 379D. New Year Letter【动态规划、暴力枚举】


题目大意:

给出如下定义: s(n)=s(n-2)+s(n-1),其中s为字符串,+为串联,比如s1="ab",s2="cd",s1+s2="abcd",s2+s1="cdab"。
给出k,x,n,m,求满足使字符串s(k)中子串“AC”的个数恰好等于x的s1,s2字符串,如果有多种可能,随意输出。

做法:

我们将“AC”其分成两个部分,一种是在s1,s2内部的“AC”,一种是在s1,s2的两端,由s1,s2结合而成的“AC”。
由于s(k)一定是由很多个s1,s2串联而成,串联处可能是s1s2,s2s1,s2s2三种。
如此,我们需要知道s(k)中s1,s2的个数,以及s1s2,s2s1,s2s2三种串联方式的分别的数量,利用动态规划即可求出;最后暴力枚举出可能的结果。遇到可能的情况即可跳出枚举,输出答案,具体做法见代码。

代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 55
using namespace std;
struct aa
{
    long long fir,las,_12,_22,_21,v; 
}dp[N];//字符串信息结构体,fir,las表示当前结构体头和尾分别是s1还是s2,__12为当前字符串由s1s2串联成的数量,其他的变量类似,v为当前字符串中s2的个数
long long k,x,n,m;
char s1[N*2],s2[N*2];
long long n1,n2;
int main()
{
    scanf("%I64d%I64d%I64d%I64d",&k,&x,&n,&m);
// 初始化  
    dp[2].v=1,dp[2].fir=2,dp[2].las=2,dp[2]._12=dp[2]._22=dp[2]._21=0;
    dp[3].v=1,dp[3].fir=1,dp[3].las=2,dp[3]._12=1,dp[3]._22=dp[3]._21=0;
    for(long long i=4;i<=k;i++)
    {
        dp[i].v=dp[i-1].v+dp[i-2].v;
        dp[i]._12=dp[i-1]._12+dp[i-2]._12;
        dp[i]._22=dp[i-1]._22+dp[i-2]._22;
        dp[i]._21=dp[i-1]._21+dp[i-2]._21;
        dp[i].fir=dp[i-2].fir,dp[i].las=dp[i-1].las;
        if(dp[i-1].fir==1&&dp[i-2].las==2) dp[i]._21++;
        if(dp[i-1].fir==2&&dp[i-2].las==2) dp[i]._22++;
        if(dp[i-1].fir==2&&dp[i-2].las==1) dp[i]._12++;
    }
    n1=dp[k-1].v,n2=dp[k].v;
    long long __12=dp[k]._12;
    long long __22=dp[k]._22;
    long long __21=dp[k]._21;

//枚举开始:    
    long long tail1=n/2,tail2=m/2;
    long long ans1=-1,ans2=-1;
    long long flag=0;//记录答案为哪种情况,为0则代表没有符合要求的s1,s2
    for(long long i=0;i<=tail1;i++)
    {
        for(long long j=0;j<=tail2;j++)
        {
            if(i*n1+j*n2>x) break;          //如果大于x则没必要枚举下去
            if(i*n1+j*n2==x){ans1=i,ans2=j,flag=1;break;}
            if(__12 && i*n1+j*n2+__12==x && !(i*2==n||j*2==m)){ans1=i,ans2=j,flag=12;break;}
            if(__22 && i*n1+j*n2+__22==x && !(j*2==m||j*2+1==m)){ans1=i,ans2=j,flag=22;break;}
            if(__21 && i*n1+j*n2+__21==x && !(i*2==n||j*2==m)){ans1=i,ans2=j,flag=21;break;}
            if(__21 && __22 && i*n1+j*n2+__21+__22==x && !(i*2==n||j*2==m||j*2+1==m)){ans1=i,ans2=j,flag=21+22;break;}
            if(__22 && __12 && i*n1+j*n2+__22+__12==x && !(i*2==n||j*2==m||j*2+1==m)){ans1=i,ans2=j,flag=12+22;break;}
            if(__21 && __12 && __22 && i*n1+j*n2+__21+__12+__22==x && !(i*2==n||j*2==m||j*2+1==m||i*2+1==n)){ans1=i,ans2=j,flag=21+22+12;break;}
            //没有必要判断__21__12的情况,当此情况满足的时候,__21__12__22一定是满足的。
        }
        if(flag) break;//一旦找到答案,就跳出
    }
    long long i=0;
    if(!flag) printf("Happy new year!\n");
    else// 分情况分别赋值给两个字符串
    {
        if(flag==1){
            for(i=0;i<ans1*2;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
            for(i=0;i<ans2*2;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
        }
        else if(flag==12){
            for(i=0;i<ans1*2;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
            s1[n-1]='A';s2[0]='C';
            for(i=1;i<ans2*2+1;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
        }
        else if(flag==22){
            s2[0]='C';
            for(i=1;i<ans2*2+1;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
            s2[m-1]='A';
            for(i=0;i<ans1*2;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
        }
        else if(flag==21){
            s1[0]='C';
            for(i=1;i<ans1*2+1;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
            for(i=0;i<ans2*2;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
            s2[m-1]='A';
        }
        else if(flag==22+21){
            s2[0]='C';
            for(i=1;i<ans2*2+1;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
            s2[m-1]='A';s1[0]='C';
            for(i=1;i<ans1*2+1;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
        }
        else if(flag==22+12){
            s2[0]='C';
            for(i=1;i<ans2*2+1;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
            s2[m-1]='A';
            for(i=0;i<ans1*2;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
            s1[n-1]='A';
        }
        else if(flag==22+12+21){
            s2[0]='C';
            for(i=1;i<ans2*2+1;i++)
                s2[i++]='A',s2[i]='C';
            for(long long j=i;j<m;j++)
                s2[j]='B';
            s2[m-1]='A';s1[0]='C';
            for(i=1;i<ans1*2+1;i++)
                s1[i++]='A',s1[i]='C';
            for(long long j=i;j<n;j++)
                s1[j]='B';
            s1[n-1]='A';
        }
    }
    cout<<s1<<endl;
    cout<<s2<<endl;
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值