A.Common Subsequence

题意

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

AC

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1005;
  4. int a[N], x, n, m, flag, t;
  5. int main() {
  6. //freopen("in.txt","r",stdin);
  7. ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
  8. cin >> t; while (t--) {
  9. cin >> n >> m;
  10. for (int i = 0; i < n; ++i)cin >> x, a[x]++;
  11. flag = 0;
  12. for (int i = 0; i < m; ++i) {
  13. cin >> x;
  14. if (a[x])
  15. flag = x;
  16. }
  17. if (flag) {
  18. cout << "YES" << endl;
  19. cout << 1 << " " << flag << endl;
  20. }
  21. else cout << "NO" << endl;
  22. }
  23. }

B.Sequential Nim

题意:

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

思路:

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

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main() {
  4. int n, t, x, flag, cnt;
  5. //freopen("in.txt", "r", stdin);
  6. ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
  7. cin >> t; while (t--) {
  8. cin >> n; cnt = 0; flag = 0;
  9. while (n--) {
  10. cin >> x;
  11. if (x == 1 && flag == 0)
  12. cnt++;
  13. if (x > 1)
  14. flag = 1;
  15. }
  16. if ((cnt % 2 == 1 && flag) || (cnt % 2 == 0 && flag == 0))
  17. cout << "Second" << endl;
  18. else
  19. cout << "First" << endl;
  20. }
  21. }

C1Prefix Flip (Easy Version)

题意;

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

思路:

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

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

C2题待补

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

题意:

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

思路:

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

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 4e3 + 10;
  4. int dp[N], d[N], a[N];
  5. int main() {
  6. //freopen("in.txt","r",stdin);
  7. ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
  8. int t, n; cin >> t; while (t--) {
  9. cin >> n;
  10. memset(dp, 0, sizeof dp);
  11. for (int i = 1; i <= 2 * n; ++i)cin >> a[i];
  12. int mx = a[1], cnt = 1, len = 0;
  13. for (int i = 2; i <= 2 * n; ++i) {
  14. if (a[i] > mx) {
  15. mx = a[i];
  16. d[++len] = cnt;
  17. cnt = 1;
  18. }
  19. else
  20. cnt++;
  21. }
  22. d[++len] = cnt;
  23. for (int i = 1; i <= len; i++)
  24. for (int j = n; j >= d[i]; j--)
  25. dp[j] = max(dp[j], dp[j - d[i]] + d[i]);
  26. if (dp[n] == n) cout << "YES" << endl;
  27. else cout << "NO" << endl;
  28. }
  29. }

E题待补