Codeforces #545 (Div. 1) B. Camp Schedule (next数组求最小循环节)

题目: https://codeforces.com/contest/1137/problem/B

题目大意:给一个01字符串S和T,不改变S中0,1的数目,重组S使得T为其子串并且尽可能多的出现

最开始以为T不能重叠,以为是个傻逼题,wa了后发现T可以重叠,就相当于让T的前缀与后缀尽可能多的重合,比如当T为101时 构造的S尽可能为10101… 观察一下不难发现,我们只需要求T的最小循环节t,然后在S中不断重复构造t就行.

T的最小循环节长度为 T.size()-next[T.size()]

代码写的很丑 不想改了()

#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<time.h>
#define bug1(g) cout<<"test: "<<g<<endl
#define bug2(g,i) cout<<"test: "<<g<<" "<<i<<endl
#define bug3(g,i,k) cout<<"test: "<<g<<" "<<i<<" "<<k<<endl
using namespace std;
typedef  unsigned long long ll;
string s,t;
int nex[500005];
void init()
{
    int k=-1,j=0;
    nex[0]=-1;
    while(j<=t.size())
    {
        if(k==-1||t[k]==t[j])
        {
            ++k;
            ++j;
            nex[j]=k;
        }
        else k=nex[k];
    }
   // for(int i =0;i<=t.size();i++)
      //  cout<<nex[i]<<" ";
  //  cout<<endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>s>>t;
    init();
    int x=0,y=0,a=0,b=0;
    for(int i =0;i<s.size();i++)
        if(s[i]=='0') x++;
        else y++;
    int tmp=t.size()-nex[t.size()];
    for(int i=0;i<tmp;i++)
    {
        if(t[i]=='0') a++;
        else b++;
    }
    int j=0,aa=a,bb=b;
    for(int i =0;i<s.size();i++)
    {
        if(j==tmp)
            aa=a,bb=b,j=0;
        if(t[j]=='0'&&x>0&&aa>0)
        {
            x--;
            aa--;
            j++;
            cout<<0;
        }
        else if(t[j]=='1'&&y>0&&bb>0)
        {
            y--;
            bb--;
            j++;
            cout<<1;
        }
        else if(x>0)
        {
            x--;
            cout<<0;
        }
        else if(y>0)
        {
            y--;
            cout<<1;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值