zoukankan      html  css  js  c++  java
  • Codeforces Round #658 (Div. 2)题解

    比赛:https://codeforces.com/contest/1382

    A. Common Subsequence

    网址:https://codeforces.com/contest/1382/problem/A

    You are given two arrays of integers (a_1,…,a_n) and (b_1,…,b_m).

    Your task is to find a non-empty array (c_1,…,c_k) that is a subsequence of (a_1,…,a_n), and also a subsequence of (b_1,…,b_m). 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 (a_1,…,a_n) ((1≤a_i≤1000)) — the elements of the first array.

    The third line of each test case contains (m) integers (b_1,…,b_m) ((1≤b_i≤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=1}^t{n_i},∑_{i=1}^t{m_i}≤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 (c_1,…,c_k) ((1≤c_i≤1000)) — the elements of the array.

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

    Example

    input

    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
    

    output

    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".


    本题是我见过CF Div. 2中A题码量最大的一道题。
    查看是否有重复的元素,输出它。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int SIZE = 1000 + 5;
    int n, m, a[SIZE], b[SIZE];
    bool vis[SIZE];
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	bool valid;
    	while(T --)
    	{
    		scanf("%d %d", &n, &m);
    		memset(vis, 0, sizeof(vis));
    		for(int i = 0; i < n; ++ i) 
    		{
    			scanf("%d", &a[i]);
    			vis[a[i]] = true;
    		}		
    		valid = false;
    		for(int i = 0; i < m; ++ i) cin >> b[i];
    		for(int i = 0; i < m; ++ i)
    		{
    			if(vis[b[i]])
    			{
    				valid = true;
    				printf("YES
    1 %d
    ", b[i]);
    				break;
    			}
    		}
    		if(!valid) puts("NO");
    	}
    	return 0;
    }
    

    B. Sequential Nim

    网址:https://codeforces.com/contest/1382/problem/B

    There are (n) piles of stones, where the (i)-th pile has (a_i) 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≤10^5)) — the number of piles.

    The second line of each test case contains (n) integers (a_1,…,a_n) ((1≤a_i≤10^9)) — (a_i) 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 (10^5).

    Output

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

    Example

    input

    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
    

    output

    First
    Second
    Second
    First
    First
    Second
    First
    

    Note

    In the first test case, the first player will win the game. His winning strategy is:

    1. 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]).
    2. 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]).
    3. 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]).
    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]).
    5. 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]).
    6. The second player will lose the game because all piles will be empty.

    • 对于只有一块的堆而言,别无选择;
    • 对于有多块饼干(石子)而言,对先手只有两种选择:全选,还是选所有的数目减一。
      我们对于情况一一考察:
    1. 所有的堆都大于1,那么先手必胜(先手对于每一个堆让它仅剩1,等剩下最后一堆直接拿走);
    2. 如果有1,我们分多种情况讨论;
    • 无前导1:先手必胜(他可以决定整个拿取的主动权);
    • 相反:(1)有奇数个前导1:后手必胜;(2)反之,先手必胜;
    • 如果所有的都是1,则n为奇数先手必胜,否则后手必胜。

    代码如下:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn = 100000 + 5;
    int n, a[maxn];
    int main()
    {
    	int T, num = 0;
    	scanf("%d", &T);
    	while(T --)
    	{
    		scanf("%d", &n);
    		for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    
    		for(int i = 1; i <= n; ++ i)
    		{
    			if(a[i] == 1)
    			{
    				++ num;
    				continue;
    			}
    			break;
    		}
    		if(num == n)
    		{
    			if(n & 1)puts("First");
    			else puts("Second");
    		}
    		else
    		{
    			if(num & 1) puts("Second");
    			else puts("First");
    		}
    		num = 0;
    	}
    	return 0;
    }
    

    C1. Prefix Flip (Easy Version)

    网址:https://codeforces.com/contest/1382/problem/C1

    This is the easy 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 (3n) 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≤1000)) — 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 (1000).

    Output

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

    Example

    input

    5
    2
    01
    10
    5
    01011
    11100
    2
    01
    01
    10
    0110011011
    1000110100
    1
    0
    1
    

    output

    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.


    这道题从后往前确定。
    考虑第(i)位,若相等,(-- i)
    若不等,(a_1)是否与之相等,若想等直接操作(flip(i)),若不等(flip(1))再进行如上操作。

    代码如下:

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    using namespace std;
    const int maxn = 1000 + 5;
    vector <int> ans;
    int n, a[maxn], b[maxn];
    void flip(int cur)
    {
    	for(int i = 1; i <= cur; ++ i) a[i] ^= 1;
    	int mid = cur >> 1;
    	for(int i = 1; i <= mid; ++ i) swap(a[i], a[1 + cur - i]);
    	return;
    }
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	while(T --)
    	{
    		ans.clear();
    		scanf("%d", &n);
    		for(int i = 1; i <= n; ++ i) scanf("%1d", &a[i]);
    		for(int i = 1; i <= n; ++ i) scanf("%1d", &b[i]);
    		for(int i = n; i > 0; -- i)
    		{
    			if(a[i] == b[i]) continue;
    			if(a[1] != a[i])
    			{
    				flip(1);
    				ans.push_back(1);
    			}
    			flip(i);
    			ans.push_back(i);
    		}
    		printf("%d ", ans.size());
    		for(int i = 0; i < ans.size(); ++ i) printf("%d ", ans[i]);
    		puts("");
    	}
    	return 0;
    }
    

    C2. Prefix Flip (Hard Version)

    网址:https://codeforces.com/contest/1382/problem/C2

    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≤10^5)) — 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 (10^5).

    Output

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

    Example

    input

    5
    2
    01
    10
    5
    01011
    11100
    2
    01
    01
    10
    0110011011
    1000110100
    1
    0
    1
    

    output

    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.


    我的做法是:对(C1)的改良版。
    (C1)的最大瓶颈是每次更改的时候操作复杂度为(T(n)),在这里我们有优化的空间!
    我们可以不进行操作(类似于延迟标记),记录每次操作时所做的贡献,例如先(flip(i))一遍再(flip(i - 1)),我们不修改前(i-1)个数的值,反之,我们将两次操作所作的贡献累加到变量上。换言之,对于前(i-1)个数而言,我们要知道现在的值,只需要(a[k] XOR)该变量即可。
    不过还没完那。怎么在(T(1))时间进行?
    考虑记录区间的首尾即可,当进行一次的时候,首尾指针互换即可。

    细节题。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int maxn = 100000 + 5;
    int n, a[maxn], b[maxn];
    vector <int> ans;
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	while(T --)
    	{
    		ans.clear();
    		scanf("%d", &n);
    		for(int i = 1; i <= n; ++ i) scanf("%1d", &a[i]);
    		for(int i = 1; i <= n; ++ i) scanf("%1d", &b[i]);
    		int delta = 0, len = n, L = 1, R = n;
    		bool dir = 0;
    		while(len)
    		{
    			if(dir)
    			{
    				int op = a[L] ^ delta;
    				if(op != b[len])
    				{
    					if(a[L] == a[R]) dir ^= 1, delta ^= 1;
    					else
    					{
    						a[R] ^= 1;
    						ans.push_back(1);
    						dir ^= 1, delta ^= 1;
    					}
    					ans.push_back(len);
    					-- R;
    				} 
    				else ++ L;
    			}
    			else
    			{
    				int op = a[R] ^ delta;
    				if(op != b[len])
    				{
    					if(a[R] == a[L]) dir ^= 1, delta ^= 1;
    					else
    					{
    						a[L] ^= 1;
    						ans.push_back(1);
    						dir ^= 1, delta ^= 1;
    					}
    					ans.push_back(len);
    					++ L;
    				}
    				else -- R;
    			}
    			-- len;
    		}
    		printf("%d ", ans.size());
    		for(int i = 0; i < ans.size(); ++ i) printf("%d ", ans[i]);
    		puts("");
    	}
    	return 0;
    } 
    

    D. Unmerge

    网址:https://codeforces.com/contest/1382/problem/D

    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 (a_1<b_1), then (merge(a,b)=[a_1]+merge([a_2,…,a_n],b)). That is, we delete the first element (a_1) of (a), merge the remaining arrays, then add (a_1) to the beginning of the result.
    If both arrays are non-empty, and (a_1>b_1), then (merge(a,b)=[b_1]+merge(a,[b_2,…,b_m])). That is, we delete the first element (b_1) of (b), merge the remaining arrays, then add (b_1) 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 (p_1,…,p_{2n}) ((1≤p_i≤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

    input

    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
    

    output

    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.


    这是我见过比较巧的dp问题。
    首先,随便找一个(p),大致模拟一遍,会发现一些规律。
    CF的题好就好在这些规律是“难以言传”的,但模拟后肯定有收获。(不代表无法解释,只限于我水平低,不能罢了)

    P 1 4 5 3 2 6
    a
    b

    考虑这个表格,
    对于(p_1),怎么放没有影响,姑且放在(a_1)处;

    对于(p_2),也可以随意放,我们就放在(b_1)

    P 1 4 5 3 2 6
    a 1
    b 4

    那这没啥规律啊?怎么构造呢???

    别着急,问题马上就到了。

    我们此时为(p_3)选位置。随便放,我们就放在(b_2)处。那(p_4)呢??

    我们不妨模拟一下过程,首先(a_1)会先被归并merge,接着因为(b_1)被归并是因为(a_2>b_1),故(p_4)就得跟着(p_3)后面、同理(p_5)也得跟着(p_4)后面走。直到(p_6)

    P 1 4 5 3 2 6
    a 1
    b 4 5

    不妨试一下其他情况。会发现规律。

    事实上,自一个数开始,这就是一个个的区间。相当于给一个数组选区间,使得区间总的长度(==n)
    典型的背包问题。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    using namespace std;
    const int SIZE = 4000 + 5;
    vector <int> segment;
    bool dp[SIZE];
    int n, p[SIZE];
    int main()
    {
    	int t;
    	scanf("%d", &t);
    	while(t --)
    	{
    		memset(dp, false, sizeof(dp));
    		dp[0] = true;
    		segment.clear();
    		scanf("%d", &n);
    		for(int i = 1; i <= n << 1; ++ i)
    		{
    			scanf("%d", &p[i]);
    		}
    		int pre = 0, num = 0;
    		for(int i = 1; i <= n << 1; ++ i)
    		{
    			if(pre < p[i])
    			{
    				if(i >= 2) segment.push_back(num);
    				num = 1;
    				pre = p[i];
    			} 
    			else ++ num;
    		}
    		for(int i = 0; i < segment.size(); ++ i)
    		{
    			for(int j = n; j; -- j)
    			{
    				if(j >= segment[i]) dp[j] |= dp[j - segment[i]];
    			}
    		}
    		if(dp[n]) puts("YES");
    		else puts("NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    码到成功——Beta冲刺随笔 day 6
    团队作业第六次——Beta冲刺
    Beta冲刺 —— 6.2
    用户调查报告
    Beta冲刺 —— 总结随笔
    Beta冲刺——测试随笔
    Beta冲刺 —— 6.1
    Beta冲刺 —— 5.31
    Beta冲刺 —— 5.30
    Beta冲刺 —— 5.29
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13377076.html
Copyright © 2011-2022 走看看