您的位置:首页 > 其它

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

2014-08-23 22:25 357 查看

题目大意:

给出如下定义: 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
;//字符串信息结构体,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: