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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章