Codeforces Round #658 (Div. 2)

A.Common Subsequence

题意

给你两组数,问你有没有相同 的书,有的话,输出最短的那组(大家都知道,1是最小的)

AC

#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
int a[N], x, n, m, flag, t;
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t; while (t--) {
		cin >> n >> m;
		for (int i = 0; i < n; ++i)cin >> x, a[x]++;
		flag = 0;
		for (int i = 0; i < m; ++i) {
			cin >> x;
			if (a[x])
				flag = x;
		}
		if (flag) {
			cout << "YES" << endl;
			cout << 1 << " " << flag << endl;
		}
		else cout << "NO" << endl;
	}
}

B.Sequential Nim

题意:

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

思路:

谁先遇到大于1的石子堆,谁就一定不会输,因为大于1的石子堆,我可以选择全拿完和留一个,这两种状态结果是互斥的,必定会有一个状态的必胜态,所以只要判断到大于1的数前面的1的数量就行,若是全1的情况,那就轮流拿,单独判断一下就行。

#include<bits/stdc++.h>
using namespace std;
int main() {
    int n, t, x, flag, cnt;
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> t; while (t--) {
        cin >> n; cnt = 0; flag = 0;
        while (n--) {
            cin >> x;
            if (x == 1 && flag == 0)
                cnt++;
            if (x > 1)
                flag = 1;
        }
        if ((cnt % 2 == 1 && flag) || (cnt % 2 == 0 && flag == 0))
            cout << "Second" << endl;
        else
            cout << "First" << endl;
    }
}

C1Prefix Flip (Easy Version)

题意;

给你两个长度相同的01字符串a,b,有一种操作,我们可以把一个字符串长度为x的前缀拿出来,把0,1互换,(就像是异或一下)然后再把这个前缀翻转(掉个头)放回到原字符串中,问我们通过几次这种操作把a转换为b。操作数小于2*n;

思路:

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

#include<bits/stdc++.h>
using namespace std;
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	string a, b; int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		cin >> a >> b; int ans = 0;	
		for (int i = 0; i < n; ++i)if (a[i] != b[i])ans++;
		cout << 3 * ans << " ";
		for (int i = 0; i < n; ++i)if (a[i] != b[i])cout << i + 1 << " 1 " << i + 1 << " ";
		cout << endl;
	}
}

C2题待补

D. Unmerge(01背包问题,1800)

题意:

对于两个数组,定义merge运算:每次把两个数组的首部的较小的那个拿出,并放到一个新的数组中。现在给定一个长度为n*2的排列,问你这个排列是否可能由两个长度为n的数组merge得到?可能则打印yes,否则no。

思路:

因为每次拿头部最小的放进新数组,所以一旦我们碰到一个数值a[i],紧跟a[i]后面的并且小于a[i]的全都应该和a[i]是同一组的,那么我们对于每次出现的这种,我们记录它们的长度。如果可能由两个长度为n的组成,那么我们可以找到一些长度,他们加起来等于n,也就是01背包问题了。

#include<bits/stdc++.h>
using namespace std;
const int N = 4e3 + 10;
int dp[N], d[N], a[N];
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t, n; cin >> t; while (t--) {
		cin >> n;
		memset(dp, 0, sizeof dp);
		for (int i = 1; i <= 2 * n; ++i)cin >> a[i];
		int mx = a[1], cnt = 1, len = 0;
		for (int i = 2; i <= 2 * n; ++i) {
			if (a[i] > mx) {
				mx = a[i];
				d[++len] = cnt;
				cnt = 1;
			}
			else
				cnt++;
		}
		d[++len] = cnt;
		for (int i = 1; i <= len; i++)
			for (int j = n; j >= d[i]; j--)
				dp[j] = max(dp[j], dp[j - d[i]] + d[i]);
		if (dp[n] == n) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
}

E题待补

posted @ 2020-07-25 17:36  RioTian  阅读(128)  评论(0编辑  收藏  举报