套题1

T1

给出一个 (n) 长的 (01) 串;
每次操作可以将一个 (0) 转化为 (1),或者反向操作;
要求最少能使所有 (0)(1) 前面的操作数;

solve

预处理关于 (1) 的前缀和
枚举 (0, 1) 的交界点进行判断

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>

using namespace std;
const int N = 1e5 + 10;

char s[N];
int A[N];

int main() {
	scanf("%s", s + 1);
	int n = strlen(s + 1);
	for(int i = 1; i <= n; i ++) 
		if(s[i] == '0') A[i] = 0;
		else A[i] = 1;
	for(int i = 1; i <= n; i ++) A[i] += A[i - 1];
	int Answer = (1 << 30);
	for(int i = 1; i <= n + 1; i ++) {
		int now = A[i - 1] + (n - i + 1) - (A[n] - A[i - 1]);
		Answer = min(Answer, now);
	}
	cout << Answer;
	return 0;
}


T2

给定 (n), 求有多少对 ((x, y)) 满足

  1. (x < y)
  2. (x, y) 中出现的 ([0, 9]) 的数码种类相同

solve

由于只要求种类相同
只需记录每个种类出现的次数
然后组合数计算即可

在记录种类时有个技巧
假设 (x) 映射出来的数为 (a)
(i) 存在于 (x) 的数码中
则对 (a)(2 ^ i)
这样的话,不会存在 (x) 不同 (a) 相同的情况
可以计算 (a <= 1024)

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;
const int size = 1024;

int n;
int f[size];
long long ans;
bool v[10];
int u[10] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) {
		int a = i, b = 0;
		memset(v, 0, sizeof v);
		while(a) v[a % 10] = 1, a /= 10;
		for(int j = 0; j <= 9; j ++) if(v[j]) b += u[j];
		f[b] ++;
	}
	for(int i = 0; i < size; i ++) ans += 1ll * f[i] * (f[i] - 1) / 2;
	cout << ans;
	return 0;
}

T3

给出长度为 (n) 的序列
求最长子序列满足
偶数项 (>) 相邻的两项,且差 (<= k)

slove

(n ^ 2) dp
(f_i) 表示第 (i) 个为奇数项时到 (i) 的最长子序列
(g_i) 表示第 (i) 个为偶数项时到 (i) 的最长子序列

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>

using namespace std;

const int N = 2e6 + 10;

int n, k, A[N], f[N], g[N];

int main() {
	cin >> n >> k;
	for(int i = 1; i <= n; i ++) cin >> A[i];
	for(int i = 1; i <= n; i ++) {
		int Max = 0;
		for(int j = 1; j < i; j ++) {
			if(A[i] <= A[j] && A[j] - A[i] >= k) {
				Max = max(Max, g[j]);
			} 
		}		
		f[i] = Max + 1;
		Max = -1;
		for(int j = 1; j < i; j ++) {
			if(A[i] >= A[j] && A[i] - A[j] >= k) {
				Max = max(Max, f[j]);
			}
		}
		g[i] = Max + 1;
	}
	int Answer = 0;
	for(int i = 1; i <= n; i ++) Answer = max(max(g[i], f[i]), Answer);
	cout << Answer;
	return 0;
}

(O(n)) 贪心

#include<bits/stdc++.h>

using namespace std;
const int maxn = 2000008;

int n, m, a[maxn];

int main() {
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; i ++) scanf("%d", a + i);
	int ans = 1, k = 0, cur = a[0];
	for(int i = 1; i < n; i ++)
		if(k) {
			if(cur - m >= a[i]) k = 0, cur = a[i], ans ++;
			else cur = max(cur, a[i]);
		} else {
			if(a[i] - m >= cur)	k = 1, cur = a[i], ans ++;
			else cur = min(cur, a[i]);
		}
	printf("%d
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/shandongs1/p/9648139.html