Codeforces Round #658 (Div. 2)题解总结

A - Common Subsequence(水)

You are given two arrays of integers a1,…,an and b1,…,bm.

Your task is to find a non-empty array c1,…,ck that is a subsequence of a1,…,an, and also a subsequence of b1,…,bm. If there are multiple answers, find one of the smallest possible length. If there are still multiple of the smallest possible length, find any. If there are no such arrays, you should report about it.

A sequence a is a subsequence of a sequence b if a can be obtained from b by deletion of several (possibly, zero) elements. For example, [3,1] is a subsequence of [3,2,1] and [4,3,1], but not a subsequence of [1,3,3,7] and [3,10,4].

Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 3t lines contain descriptions of test cases.

The first line of each test case contains two integers n and m (1≤n,m≤1000) — the lengths of the two arrays.

The second line of each test case contains n integers a1,…,an (1≤ai≤1000) — the elements of the first array.

The third line of each test case contains m integers b1,…,bm (1≤bi≤1000) — the elements of the second array.

It is guaranteed that the sum of n and the sum of m across all test cases does not exceed 1000 (∑i=1tni,∑i=1tmi≤1000).

Output
For each test case, output “YES” if a solution exists, or “NO” otherwise.

If the answer is “YES”, on the next line output an integer k (1≤k≤1000) — the length of the array, followed by k integers c1,…,ck (1≤ci≤1000) — the elements of the array.

If there are multiple solutions with the smallest possible k, output any.

Example
inputCopy
5
4 5
10 8 6 4
1 2 3 4 5
1 1
3
3
1 1
3
2
5 3
1000 2 2 2 3
3 1 5
5 5
1 2 3 4 5
1 2 3 4 5
outputCopy
YES
1 4
YES
1 3
NO
YES
1 3
YES
1 2
Note
In the first test case, [4] is a subsequence of [10,8,6,4] and [1,2,3,4,5]. This array has length 1, it is the smallest possible length of a subsequence of both a and b.

In the third test case, no non-empty subsequences of both [3] and [2] exist, so the answer is “NO”.
题意:
给你两组序列,问你有没有相同的序列,有的话,输出最短的那组

思路:
大家都知道,1是最小的,只要找到有一个相同的元素输出即可。没有相同的则输出“NO”

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
int a[N],b[N];
int main() 
{
	int t, n,m, ans=0;
	cin>>t;
	while (t--)
	{
		bool flag = 1;
		cin >> n >> m;
		for (int i = 0; i < n; i++)
			cin >> a[i];
		for (int i = 0; i < m; i++)
			cin >> b[i];
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				if (a[i] == b[j])
				{
					ans = a[i];
					flag = 0;
					break;
				}
			}
			if (flag == 0)break;
		}
		if (flag == 0)
		{
			cout << "YES" << endl;
			cout << 1 << " " << ans << endl;
		}
		else
			cout << "NO" << endl;
	}
	return 0;
}

B - Sequential Nim

There are n piles of stones, where the i-th pile has ai stones. Two people play a game, where they take alternating turns removing stones.

In a move, a player may remove a positive number of stones from the first non-empty pile (the pile with the minimal index, that has at least one stone). The first player who cannot make a move (because all piles are empty) loses the game. If both players play optimally, determine the winner of the game.

Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2t lines contain descriptions of test cases.

The first line of each test case contains a single integer n (1≤n≤105) — the number of piles.

The second line of each test case contains n integers a1,…,an (1≤ai≤109) — ai is equal to the number of stones in the i-th pile.

It is guaranteed that the sum of n for all test cases does not exceed 105.

Output
For each test case, if the player who makes the first move will win, output “First”. Otherwise, output “Second”.

Example
inputCopy
7
3
2 5 4
8
1 1 1 1 1 1 1 1
6
1 2 3 4 5 6
6
1 1 2 1 2 2
1
1000000000
5
1 2 2 1 1
3
1 1 1
outputCopy
First
Second
Second
First
First
Second
First
Note
In the first test case, the first player will win the game. His winning strategy is:

The first player should take the stones from the first pile. He will take 1 stone. The numbers of stones in piles will be [1,5,4].
The second player should take the stones from the first pile. He will take 1 stone because he can’t take any other number of stones. The numbers of stones in piles will be [0,5,4].
The first player should take the stones from the second pile because the first pile is empty. He will take 4 stones. The numbers of stones in piles will be [0,1,4].
The second player should take the stones from the second pile because the first pile is empty. He will take 1 stone because he can’t take any other number of stones. The numbers of stones in piles will be [0,0,4].
The first player should take the stones from the third pile because the first and second piles are empty. He will take 4 stones. The numbers of stones in piles will be [0,0,0].
The second player will lose the game because all piles will be empty.

题意:
两个人玩区石子游戏,有n堆,第i堆有a[i]个,每个人只能按堆的顺序拿,就是前面这堆没有拿完,不能拿下一堆。谁先不能拿就输了。

思路:
这个明显的先手必胜,因为先手拿的话可以每次都把每堆拿剩下一个,然后下一个拿只能拿最后一个,然后到了最后一堆直接拿完。
但是前边出现了1的话就会出现变化,记录出现 1 的个数,如果奇数个 1那么先手变后手,后手变先手。还有一种特殊情况就就是全是1的情况。

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
ll a[N],b[N];
int main() 
{
	int t, n,m, ans;
	cin>>t;
	while (t--)
	{
		int n; 
		cin >> n; int i;
		int s = 0;
		for (i = 1; i <= n; i++)
			cin >> a[i];
		for (i = 1; i <= n; i++)
		{
			if (a[i] == 1)s++;
			else break;
		}
		if (s == n)
		{
			if (s % 2 == 0)
				cout << "Second" << endl;
			else cout << "First" << endl;
		}
		else
		{
			if (s % 2 == 0)
				cout << "First" << endl;
			else cout << "Second" << endl;
		}
	}
	return 0;
}

C - Prefix Flip (Easy & Hard Version)

This is the hard version of the problem. The difference between the versions is the constraint on n and the required number of operations. You can make hacks only if all versions of the problem are solved.

There are two binary strings a and b of length n (a binary string is a string consisting of symbols 0 and 1). In an operation, you select a prefix of a, and simultaneously invert the bits in the prefix (0 changes to 1 and 1 changes to 0) and reverse the order of the bits in the prefix.

For example, if a=001011 and you select the prefix of length 3, it becomes 011011. Then if you select the entire string, it becomes 001001.

Your task is to transform the string a into b in at most 2n operations. It can be proved that it is always possible.

Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 3t lines contain descriptions of test cases.

The first line of each test case contains a single integer n (1≤n≤105) — the length of the binary strings.

The next two lines contain two binary strings a and b of length n.

It is guaranteed that the sum of n across all test cases does not exceed 105.

Output
For each test case, output an integer k (0≤k≤2n), followed by k integers p1,…,pk (1≤pi≤n). Here k is the number of operations you use and pi is the length of the prefix you flip in the i-th operation.

Example
inputCopy
5
2
01
10
5
01011
11100
2
01
01
10
0110011011
1000110100
1
0
1
outputCopy
3 1 2 1
6 5 2 5 3 1 2
0
9 4 1 2 10 4 1 2 1 5
1 1
Note
In the first test case, we have 01→11→00→10.

In the second test case, we have 01011→00101→11101→01000→10100→00100→11100.

In the third test case, the strings are already the same. Another solution is to flip the prefix of length 2, which will leave a unchanged.

题意:
给你两个长度相同的01字符串a,b,有一种操作,我们可以把一个字符串长度为x的前缀拿出来,把0,1互换,然后再把这个前缀掉个头放回到原字符串中,要求在 3(2)n 步内把给定 a 串变成 b 串。

思路:
因为每次变的都是前缀,也就是说,后面的不会动了,那么我们可以从后往前判断。遇到不同的,就判断a开头位置和b当前位置(因为不同就要进行”异或“然后翻转,会把第一个数翻转到当前位置上,所以判断a第一个位置和b当前位置)如果第一位置和当前位置相同,要把第一位置单独转一下,(因为相同,异或再转过来就不同了)记录一下每次翻转的位置就是答案。

C1数据较小可以直接暴力模拟,C2为了降低复杂度就要记录当前所翻转的区间。

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 1e5 + 7;
char a[N], b[N];
int ans[2 * N];
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        cin >> a;
        cin >> b;
        int num = 0;
        int l = 0, r = n - 1;
        int flog = 0;
        int fz = 0;
        for (int i = n - 1; i >= 0; i--)
        {

            if (flog == 0)
            {
                if ((b[i] != a[r] && fz % 2 == 0) || (fz % 2 && b[i] == a[r]))
                {
                    if ((b[i] == a[l] && fz % 2 == 0) || (b[i] != a[l] && fz % 2))
                    {
                        ans[num++] = 1;
                    }
                    ans[num++] = i + 1;
                    fz++;
                    flog = 1;
                    l++;
                }
                else
                {
                    r--;
                }
            }
            else
            {
                if ((b[i] != a[l] && fz % 2 == 0) || (b[i] == a[l] && fz % 2))
                {
                    if ((b[i] == a[r] && fz % 2 == 0) || (b[i] != a[r] && fz % 2))
                    {
                        ans[num++] = 1;
                    }
                    ans[num++] = i + 1;
                    fz++;
                    flog = 0;
                    r--;
                }
                else
                {
                    l++;
                }
            }
        }
        printf("%d\n", num);
        for (int i = 0; i < num; i++)
            printf("%d ", ans[i]);
        if (num)printf("\n");
    }
    return 0;
}

D - Unmerge

Let a and b be two arrays of lengths n and m, respectively, with no elements in common. We can define a new array merge(a,b) of length n+m recursively as follows:

If one of the arrays is empty, the result is the other array. That is, merge(∅,b)=b and merge(a,∅)=a. In particular, merge(∅,∅)=∅.
If both arrays are non-empty, and a1<b1, then merge(a,b)=[a1]+merge([a2,…,an],b). That is, we delete the first element a1 of a, merge the remaining arrays, then add a1 to the beginning of the result.
If both arrays are non-empty, and a1>b1, then merge(a,b)=[b1]+merge(a,[b2,…,bm]). That is, we delete the first element b1 of b, merge the remaining arrays, then add b1 to the beginning of the result.
This algorithm has the nice property that if a and b are sorted, then merge(a,b) will also be sorted. For example, it is used as a subroutine in merge-sort. For this problem, however, we will consider the same procedure acting on non-sorted arrays as well. For example, if a=[3,1] and b=[2,4], then merge(a,b)=[2,3,1,4].

A permutation is an array consisting of n distinct integers from 1 to n in arbitrary order. For example, [2,3,1,5,4] is a permutation, but [1,2,2] is not a permutation (2 appears twice in the array) and [1,3,4] is also not a permutation (n=3 but there is 4 in the array).

There is a permutation p of length 2n. Determine if there exist two arrays a and b, each of length n and with no elements in common, so that p=merge(a,b).

Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2t lines contain descriptions of test cases.

The first line of each test case contains a single integer n (1≤n≤2000).

The second line of each test case contains 2n integers p1,…,p2n (1≤pi≤2n). It is guaranteed that p is a permutation.

It is guaranteed that the sum of n across all test cases does not exceed 2000.

Output
For each test case, output “YES” if there exist arrays a, b, each of length n and with no common elements, so that p=merge(a,b). Otherwise, output “NO”.

Example
inputCopy
6
2
2 3 1 4
2
3 1 2 4
4
3 2 6 1 5 7 8 4
3
1 2 3 4 5 6
4
6 1 3 7 4 5 8 2
6
4 3 2 5 1 11 9 12 8 6 10 7
outputCopy
YES
NO
YES
YES
NO
NO
Note
In the first test case, [2,3,1,4]=merge([3,1],[2,4]).

In the second test case, we can show that [3,1,2,4] is not the merge of two arrays of length 2.

In the third test case, [3,2,6,1,5,7,8,4]=merge([3,2,8,4],[6,1,5,7]).

In the fourth test case, [1,2,3,4,5,6]=merge([1,3,6],[2,4,5]), for example.

题意:
给你一个长度为2n的数组,为你是不是由两个为n的数组构成的。
构成规则:
假设两个数组a,b,长度分别是n,m;每次取两个数组的最小值到新数组。
最后新数组长度为(n+m)。比如a(3,1),b(2,4),a+b=(2,3,1,4).

思路:
其实就是一个小背包,我们可以发现每次去数,只能取到下一个大于当前数的位置,那么我们记录一下这些数的数量,记录完了之后,我们可以选择每个区间取或者不取,取就放a数组,不取就放b数组,最后我们只需要判断能不能构成长度为n的a数组就行

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
int dp[4005];
int a[4005];
int v[4005];
int main()
{
    int t;
    cin>>t;
    while (t--)
    {
        int n;
        cin>>n;
        int tot = 0, k = 1;
        for (int i = 1; i <= 2 * n; i++)
        {
            cin>>a[i];
            if (a[i] > a[k])
            {
                v[++tot] = i - k;
                k = i;
            }
        }
        v[++tot] = 2 * n + 1 - k;
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for (int i = 1; i <= tot; i++)
        {
            for (int j = n; j >= v[i]; j--)
            {
                dp[j] = max(dp[j - v[i]], dp[j]);
            }
        }
        if (dp[n])
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}

总结

这场比赛的难度要比上一次的低多了,回了口血。第一题完全就是看完直接出答案那种,第二题也感觉还好。第三题一开始读题懵了,没看懂题目什么意思。看了老半天才看懂,然后想了一会就睡着了…,最近老困了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值