B. Camp Schedule(KMPnext数组)

Problem - 1137B - Codeforces

在全国范围内广为人知的春季编程训练营即将开始。因此,所有友好的策展人和教师团队开始组成营地的时间表。经过不断的讨论,他们想出了一个时间表,可以表示为一个二进制字符串,其中第i个符号是 "1",如果学生将在第i天写比赛,"0",如果他们将有一天休息。

在最后时刻,Gleb说,如果夏令营按照时间表t(可以用与时间表s相同的格式来描述)运行,那么它将是最有成效的。由于当前的天数可能与时间表t中的天数不同,Gleb要求营地的时间表必须被改变,使t在其中作为子串出现的次数达到最大可能。同时,比赛日和休息日的数量不应改变,只是它们的顺序可以改变。

你能以最佳方式重新安排时间表吗?

输入
第一行包含字符串s (1⩽|s|⩽500000),表示营地日程表的当前项目。

第二行包含字符串t (1⩽|t|⩽500000),表示Gleb认为的最佳时间表。

字符串s和t只包含字符'0'和'1'。

输出
打印的计划表应该只包含字符'0'和'1',零的数量应该等于s中零的数量,一的数量应该等于s中一的数量。

如果有多个最佳时间表,则打印其中任何一个。

例子
inputCopy
101101
110
outputCopy
110110
输入副本
10010110
100011
输出拷贝
01100011
输入副本
10
11100
输出拷贝
01
注意
在第一个例子中,有两个出现,一个从第一位置开始,一个从第四位置开始。

在第二个例子中,只有一个从第三位开始的出现。注意,答案不是唯一的。例如,如果我们把第一天(即休息日)移到最后一个位置,t的出现次数不会改变。

在第三个例子中,甚至不可能出现一个。

题解:

贪心是写不了这道题的

假如子串是101这种

应该10101这样构造

我们每次应该找到其最大后缀与前缀相等的字符串的长度,其实就是ne数组

我们构建一个t串的ne数组,寻找一下最大前缀和后缀所匹配的地方,然后在这个地方后面的一个单位继续构造即可,因为都匹配了,所以上一个构造好的子串的后缀,就可以充当下一个需要构造的子串的前缀,这样构造的话,最后答案一定是最优解 

#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<stack>
#include<set>
using namespace std;
#define int long long
typedef pair<int,int> PII;
const int N = 1e6 + 10;
char a[N],b[N],ans[N];
int cnt[N];
int ne[N];
void solve()
{
	cin >> a >> b;
	int n = strlen(a);
	int m = strlen(b);
	for(int i = 0; i< n;i++)
	{
		cnt[a[i] - '0']++;
	}
	ne[0] = -1;
	int i = 0,j = -1;
	while(i < m)
	{
		if(j == -1||b[j] == b[i])
		{
			ne[++i] = ++j;
		}
		else
		j = ne[j];
	}
	for(int i = 0,j = 0;i < n;i++,j++)
	{
		if(j == m)
		j = ne[j];
		if(cnt[b[j] - '0'])
		{
			ans[i] = b[j];
			cnt[b[j] - '0']--;
		}
		else
		{
			ans[i] = '0' + ((b[j] - '0')^1);
			cnt[(b[j]-'0')^1]--;
		} 
	}
	cout << ans;
	
}
//1 -7 1 -7
signed main(){
//	ios::sync_with_stdio(false);
//	cin.tie(0);
//	cout.tie(0);
	int t = 1;
//	cin >> t;
    while(t--)
	{

		solve();
	} 
}
//3 3 2 2 1 0
//1 2 1 1 1 0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值