题目链接:https://vjudge.net/contest/361017#problem/F
http://codeforces.com/problemset/problem/1137/B
题意:在一个母字符串a中,尽可能地拼出拼出最多要求的字符串b,同时母字符串可以重新排序,b在a中可以重叠一部分但不可以完全重叠。
如 10101中可以看成2个101
解题思路:
直接利用KMP来找字符串匹配,注意这里我是去找len-1的位置的最大前缀后缀(重叠时必须要求后缀从最后一位就有重叠,且这样可以最大化的利用重叠,节省01来给后面的拼凑),然后先在a中放置一个b,之后直接利用len-1地方的最大前缀后缀的那一个点进行后序添加就可以。
注意点:
注意字符串b中1的个数为0或者0的个数为0的情况(除数不可以为0)
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
#define maxs 500050
int Next[maxs];
int mark[maxs];
string s;
string t;
int s0,s1;
int t0,t1;
int m0,m1;
int lens,lent;
void get_next()
{
Next[0]=-1;
for (int i=1;i<lent;i++){
int j=Next[i-1];
while ((t[j+1]!=t[i])&&(j>-1))
j=Next[j];
if (t[j+1]==t[i])
Next[i]=j+1;
else
Next[i]=-1;
}
}
int main()
{
cin>>s;
cin>>t;
lens=s.size();
for(int i=0;i<lens;i++)
{
if(s[i]=='0')
s0++;
else
s1++;
}
lent=t.size();
for(int i=0;i<lent;i++)
{
if(t[i]=='0')
t0++;
else
t1++;
}
get_next();
int last=Next[lent-1];
for(int i=0;i<=last;i++)
{
if(t[i]=='0')
m0++;
else
m1++;
}
m0=t0-m0;
m1=t1-m1;
if(s0<t0||s1<t1)
{
for(int i=0;i<s0;i++)
printf("0");
for(int i=0;i<s1;i++)
printf("1");
cout<<endl;
}
else if(m0||m1)
{
s0-=t0;
s1-=t1;
cout<<t;
int p;
if(m0!=0&&m1!=0)
p=min(s0/m0,s1/m1);
else if(m0==0&&m1!=0)
p=s1/m1;
else if(m0!=0&&m1==0)
p=s0/m0;
s0-=p*m0;
s1-=p*m1;
string temp=t.substr(last+1,lent-last-1);
for(int i=0;i<p;i++)
cout<<temp;
for(int i=0;i<s0;i++)
printf("0");
for(int i=0;i<s1;i++)
printf("1");
cout<<endl;
}
else
{
int p=maxs;
if(t0!=0)
p=min(p,s0/t0);
if(t1!=0)
p=min(p,s1/t1);
s0-=p*t0;
s1-=p*t1;
for(int i=0;i<p;i++)
cout<<t;
for(int i=0;i<s0;i++)
printf("0");
for(int i=0;i<s1;i++)
printf("1");
cout<<endl;
}
return 0;
}