Codeforces Round #811 (Div. 3) D ~ E

D

题意

给定一个长字符串和n个短字符串,要求将n个短字符串任意顺序任意次数的拼成长字符串

样例
bababa
2
ba
aba
答案是 可以是 ba aba ba(可重叠)

思路

将每个短字符串在长字符串的出现的区间都存下来,我们就得到了一堆区间,只需要再做一个区间合并成1 ~ n 的区间并记录答案

代码实现

struct node
{
	int l, r, k;
} seg[N];
bool cmp (node a, node b)
{
	if (a.l != b.l)
		return a.l < b.l;
	else return a.r > b.r;
}
void solve()
{
	string t;
	cin >> t;
	int m = t.size();
	int n;
	cin >> n;
	int cnt = 0;
	
	for (int i = 1 ; i <= n ; i ++)
	{
		string str;
		cin >> str;
		int len = str.size();
		
		for (int j = 0; j <= m - len; j ++)
			if (str == t.substr (j, len))
				seg[cnt ++] = {j + 1, j + len, i};
	}
	
	sort (seg, seg + cnt, cmp);
		
	int res = 0;
	bool ok = false;
	int st = 0, ed = m;
	vector<PII> ans;
	
	for (int i = 0; i < cnt; i ++)
	{
		int j = i, r = -2e9;
		int now = -1;
		
		while (j < cnt and seg[j].l <= st + 1)
		{	
			if (r < seg[j].r)
			{
				r = seg[j].r ;
				now = j;
			}
			
			j ++;
		}
		
		if (r < st)
		{
			res = -1;
			break;
		}
		
		res ++;
		
		if (r >= ed)
		{
			ok = true;
			
			if (now != -1) ans.push_back ({seg[now].k, seg[now].l});
			break;
		}
		
		if (now != -1) ans.push_back ({seg[now].k, seg[now].l});
		st = r;
		i = j - 1;
	}
	
	if (!ok)
	{
		cout << -1 << '\n';
		return ;
	}
	
	cout << res << '\n';
	
	for (int i = 0; i < ans.size(); i ++)
		cout << ans[i].x << ' ' << ans[i].y << '\n';
		
	for (int i = 0; i < cnt ; i ++)
		seg[i].l = seg[i].r = seg[i].k = 0;
}

E

题意

给定一个序列,对于序列的每个数可以进行的操作 加上这个数mod10的值
问经过任意次数后序列的所有数能不能相等

思路

可以发现对于某个数来说它进行了足够多次这个操作,所得到的数 mod 20 的数是一个循环序列,而且只能分成两个组,我们只需预处理这两组数然后判断整个序列里的数mod 20 后是不是都在一个组即可

注意特判 5 只能变成 10 也就是个位为5的数只能向上 + 5, 个位为0 的数不能改变

代码实现

unordered_set<int> S =
{
	2, 4, 8, 16
};
void solve()
{
	int n;
	cin >> n;
	PII sp = {-1, 0}; bool check = true;
	
	for (int i = 1 ; i <= n ; i ++)
		cin >> a[i];
	// 特判 5 和 10 	
	for (int i = 1 ; i <= n ; i ++)
		if (a[i] % 10 == 5 or a[i] % 10 == 0)
		{
			if (sp.x == -1) sp.x = (a[i] + 5) / 10, sp.y = 1;
			else if (sp.x == (a[i] + 5) / 10) sp.y ++;
		}
	// 将所有奇数变成偶数在mod 20(因为只预处理了偶数集合)
	for (int i = 1 ; i <= n ; i ++)
	{
		if (a[i] & 1) a[i] = a[i] + a[i] % 10;
		
		a[i] %= 20;
	}
	if (sp.x != -1)
	{
		if (sp.y == n)
			cout << "Yes\n";
		else cout << "No\n";
		
		return ;
	}
	
	bool isin = S.count (a[1]);
	
	for (int i = 2 ; i <= n ; i ++)
		if (isin != S.count (a[i]))
		{
			cout << "No\n";
			return ;
		}
		
	cout << "Yes\n";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值