因为cf上一堆水题,每个单独开一篇博客感觉不太好,就直接放一起好了。
CF1096D Easy Problem
给定字符串,每个位置删除要代价。求最小代价使之不含子序列"hard"。
设f[i][f]表示前i个删到只匹配f位子序列的最小代价。转移看代码吧。O(n)

1 #include <bits/stdc++.h>
2
3 typedef long long LL;
4 const int N = 100010;
5
6 int a[N];
7 LL f[N][5];
8 char str[N];
9
10 int main() {
11 int n;
12 scanf("%d", &n);
13 scanf("%s", str + 1);
14 for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
15
16 int tag = 0;
17 for(int i = 1; i <= n; i++) {
18 if(tag == 0 && str[i] == 'h') tag++;
19 if(tag == 1 && str[i] == 'a') tag++;
20 if(tag == 2 && str[i] == 'r') tag++;
21 if(tag == 3 && str[i] == 'd') tag++;
22 }
23 if(tag != 4) {
24 printf("0\n");
25 return 0;
26 }
27
28 for(int i = 1; i <= n; i++) {
29 f[i][0] = f[i - 1][0] + a[i] * (str[i] == 'h');
30 f[i][1] = f[i - 1][1] + a[i] * (str[i] == 'a');
31 f[i][2] = f[i - 1][2] + a[i] * (str[i] == 'r');
32 f[i][3] = f[i - 1][3] + a[i] * (str[i] == 'd');
33 if(str[i] == 'h') f[i][1] = std::min(f[i][1], f[i - 1][0]);
34 if(str[i] == 'a') f[i][2] = std::min(f[i][2], f[i - 1][1]);
35 if(str[i] == 'r') f[i][3] = std::min(f[i][3], f[i - 1][2]);
36 }
37
38 LL ans = std::min(std::min(f[n][0], f[n][1]), std::min(f[n][2], f[n][3]));
39
40 printf("%lld\n", ans);
41 return 0;
42 }
CF1036C Classy Numbers
问[l, r]之间有多少个数满足非0数码不超过三个。
裸数位DP......注意每次读完要把char数组清空...

1 /**
2 * There is no end though there is a start in space. ---Infinity.
3 * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
4 * Only the person who was wisdom can read the most foolish one from the history.
5 * The fish that lives in the sea doesn't know the world in the land.
6 * It also ruins and goes if they have wisdom.
7 * It is funnier that man exceeds the speed of light than fish start living in the land.
8 * It can be said that this is an final ultimatum from the god to the people who can fight.
9 *
10 * Steins;Gate
11 */
12
13 #include <bits/stdc++.h>
14
15 typedef long long LL;
16 const int N = 25;
17
18 LL f[N][5][2];
19 char str[N], str1[N], str2[N];
20
21 LL DFS(int k, int cnt, int z) {
22 if(cnt > 3) return 0;
23 if(!k) {
24 return 1;
25 }
26 if(f[k][cnt][z] != -1) {
27 return f[k][cnt][z];
28 }
29 LL ans = 0;
30 if(cnt < 3) {
31 for(int i = 1; i <= 9; i++) {
32 ans += DFS(k - 1, cnt + 1, 1);
33 }
34 }
35 ans += DFS(k - 1, cnt, z);
36 return f[k][cnt][z] = ans;
37 }
38
39 LL DFS_2(int k, int cnt, int z) {
40 if(cnt > 3) return 0;
41 if(!k) return 1;
42 int lm = str[k] - '0';
43 //printf("k = %d cnt = %d z = %d lm = %d \n", k, cnt, z, lm);
44 LL ans = DFS_2(k - 1, cnt + (lm != 0), z | (lm != 0));
45 if(lm) {
46 ans += DFS(k - 1, cnt, z);
47 }
48 for(int i = 1; i < lm; i++) {
49 ans += DFS(k - 1, cnt + 1, 1);
50 }
51 return ans;
52 }
53 /*
54 1
55 29000000000091 29000000000099
56
57 */
58 inline void dec(int &n) {
59 for(int i = 1; i <= n; i++) {
60 if(str[i] != '0') {
61 str[i]--;
62 break;
63 }
64 else str[i] = '9';
65 }
66 if(str[n] == '0') n--;
67 return;
68 }
69
70 int main() {
71 memset(f, -1, sizeof(f));
72 LL l, r;
73 int T;
74 scanf("%d", &T);
75 for(int i = 1; i <= T; i++) {
76 scanf("%s%s", str1 + 1, str2 + 1);
77 int n = strlen(str2 + 1);
78 memcpy(str + 1, str2 + 1, sizeof(char) * n);
79 std::reverse(str + 1, str + n + 1);
80
81 /*for(int j = 1; j <= n; j++) {
82 putchar(str[j]);
83 }
84 puts("");*/
85
86 LL ans = DFS_2(n, 0, 0);
87 //printf("temp ans = %lld \n", ans);
88 memset(str2 + 1, 0, n * sizeof(char));
89 n = strlen(str1 + 1);
90 memcpy(str + 1, str1 + 1, n * sizeof(char));
91 std::reverse(str + 1, str + n + 1);
92 dec(n);
93
94 /*for(int j = 1; j <= n; j++) {
95 putchar(str[j]);
96 }
97 puts("");*/
98
99 ans -= DFS_2(n, 0, 0);
100 printf("%lld\n", ans);
101 memset(str1 + 1, 0, n * sizeof(char));
102 }
103
104 return 0;
105 }
CF1132C Painting the Fence
给定n个区间,选出n - 2个区间使它们覆盖的总长度最大。转为删去两个区间。
去重 + 排序。考虑到答案要么相邻要么不相邻,相邻的预处理前后缀覆盖总长之后直接枚举。
预处理出只删每个区间的时候的覆盖减少量为di。当不相邻的时候,考虑到减少总量就是他们两个的di之和。
于是枚举一个区间,拿一个数据结构维护[1, i - 2]之间的最小d值即可。
注意答案不能比总长度还优。复杂度O(nlogn) / O(n)

1 /**
2 * There is no end though there is a start in space. ---Infinity.
3 * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
4 * Only the person who was wisdom can read the most foolish one from the history.
5 * The fish that lives in the sea doesn't know the world in the land.
6 * It also ruins and goes if they have wisdom.
7 * It is funnier that man exceeds the speed of light than fish start living in the land.
8 * It can be said that this is an final ultimatum from the god to the people who can fight.
9 *
10 * Steins;Gate
11 */
12
13 #include <bits/stdc++.h>
14
15 const int N = 5010;
16
17 struct Node {
18 int l, r;
19 inline bool operator < (const Node &w) const {
20 if(l != w.l) return l < w.l;
21 return r > w.r;
22 }
23 }node[N], stk[N]; int top;
24
25 int n, m, sl[N], sr[N], del[N], pw[N], ST[N][20];
26
27 namespace t1 {
28 int d[N];
29 inline void solve() {
30 for(int i = 1; i <= n; i++) {
31 d[node[i].l]++;
32 d[node[i].r + 1]--;
33 }
34 int ans = 0, now = 0;
35 for(int i = 1; i <= m; i++) {
36 now += d[i];
37 ans += (now > 0);
38 }
39 printf("%d\n", ans);
40 return;
41 }
42 }
43
44 namespace t2 {
45 inline void solve() {
46 int ans = 0;
47 for(int i = 1; i <= n; i++) {
48 ans = std::max(ans, std::min(sl[i - 1] + sr[i + 1], sr[1]));
49 }
50 printf("%d\n", ans);
51 return;
52 }
53 }
54
55 inline void prework() {
56 for(int i = 1; i <= n; i++) { /// get sl del
57 sl[i] = sl[i - 1] + node[i].r - std::max(node[i].l, node[i - 1].r + 1) + 1;
58 del[i] = std::min(node[i].r, node[i + 1].l - 1) - std::max(node[i].l, node[i - 1].r + 1) + 1;
59 del[i] = std::max(del[i], 0);
60 }
61 for(int i = n; i >= 1; i--) { /// get sr
62 sr[i] = sr[i + 1] + std::min(node[i].r, node[i + 1].l - 1) - node[i].l + 1;
63 }
64 return;
65 }
66
67 inline void prework2() {
68 for(int i = 2; i <= n; i++) {
69 pw[i] = pw[i >> 1] + 1;
70 }
71 for(int i = 1; i <= n; i++) ST[i][0] = del[i];
72 for(int j = 1; j <= pw[n]; j++) {
73 for(int i = 1; i + (1 << j) - 1 <= n; i++) {
74 ST[i][j] = std::min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
75 }
76 }
77 return;
78 }
79
80 inline int getMin(int l, int r) {
81 if(l > r) return 0x3f3f3f3f;
82 int t = pw[r - l + 1];
83 return std::min(ST[l][t], ST[r - (1 << t) + 1][t]);
84 }
85
86 int main() {
87 scanf("%d%d", &m, &n);
88 for(int i = 1; i <= n; i++) {
89 scanf("%d%d", &node[i].l, &node[i].r);
90 }
91
92 std::sort(node + 1, node + n + 1);
93 int k = 2;
94 for(int i = 1; i <= n; i++) {
95 if(top && stk[top].r >= node[i].r) {
96 k--;
97 continue;
98 }
99 stk[++top] = node[i];
100 }
101 n = top;
102 memcpy(node + 1, stk + 1, n * sizeof(Node));
103
104 if(k <= 0) {
105 t1::solve();
106 return 0;
107 }
108 node[n + 1].l = node[n + 1].r = 0x3f3f3f3f;
109 prework();
110
111 if(k == 1) {
112 t2::solve();
113 return 0;
114 }
115
116 /// solve
117
118 int ans = 0;
119 for(int i = 1; i < n; i++) { /// choose i i + 1
120 ans = std::max(ans, std::min(sl[i - 1] + sr[i + 2], sr[1]));
121 }
122 /// not neighbor
123
124 prework2();
125
126 for(int i = 1; i <= n; i++) {
127 ans = std::max(ans, sr[1] - del[i] - getMin(1, i - 2));
128 }
129 printf("%d\n", ans);
130 return 0;
131 }
CF1132F Clear the String
给定字符串,一次可以删去连续的一段相同字符,问最少多少次删光。
有一个很直观的想法是f[l][r][k]表示把[l, r]删成k个str[l]的最小代价,发现不好O(1)转移...
然后又考虑f[l][r][k]表示[l, r]右端加上k个str[r]之后删去的最小代价,也不会转移...
尝试n2状态,发现这个k,完全没必要记具体个数,因为无论多少个都是一次删掉。
于是采用CF1025D的套路,fa[l][r]表示把[l, r]删成只剩str[l - 1]的最小代价,fb是str[r + 1],ans是删光的最小代价。
转移fa的时候考虑str[r]和str[l - 1]是否相同并以此转移。转移ans的时候选出一个位置,左边的fb + 右边的fa转移。

1 #include <bits/stdc++.h>
2
3 const int N = 510;
4
5 int fa[N][N], fb[N][N], ans[N][N];
6 char str[N];
7
8 inline void exmin(int &a, const int &b) {
9 if(a > b) a = b;
10 return;
11 }
12
13 int main() {
14 memset(fa, 0x3f, sizeof(fa));
15 memset(fb, 0x3f, sizeof(fb));
16 memset(ans, 0x3f, sizeof(ans));
17 int n;
18 scanf("%d", &n);
19 scanf("%s", str + 1);
20 for(int i = 1; i <= n; i++) {
21 fa[i][i] = (str[i] != str[i - 1]);
22 fb[i][i] = (str[i] != str[i + 1]);
23 ans[i][i] = 1;
24 }
25 for(int len = 2; len <= n; len++) {
26 for(int l = 1; l + len - 1 <= n; l++) {
27 int r = l + len - 1;
28 /// fa[l][r] fb[l][r] ans[l][r]
29 if(str[r] == str[l - 1]) {
30 exmin(fa[l][r], fa[l][r - 1]);
31 }
32 else {
33 for(int k = l; k < r; k++) {
34 exmin(fa[l][r], fa[l][k] + ans[k + 1][r]);
35 }
36 }
37 if(str[l] == str[r + 1]) {
38 exmin(fb[l][r], fb[l + 1][r]);
39 }
40 else {
41 for(int k = l; k < r; k++) {
42 exmin(fb[l][r], ans[l][k] + fb[k + 1][r]);
43 }
44 }
45 for(int k = l + 1; k < r; k++) {
46 exmin(ans[l][r], fb[l][k - 1] + fa[k + 1][r] + 1);
47 }
48 exmin(ans[l][r], fa[l + 1][r] + 1);
49 exmin(ans[l][r], fb[l][r - 1] + 1);
50 exmin(fa[l][r], ans[l][r]);
51 exmin(fb[l][r], ans[l][r]);
52 //printf("[%d %d] l = %d r = %d ans = %d \n", l, r, fa[l][r], fb[l][r], ans[l][r]);
53 }
54 }
55 printf("%d\n", ans[1][n]);
56 return 0;
57 }
然而本题还有多种简单一点的方法......
就设f[l][r]表示把[l, r]删光的代价,考虑str[l]是如何被删的。显然要么是单独被删,要么是跟某些位置一起删。不妨设一起删的位置中第二个是k。
枚举这个k,于是答案就是f[l + 1][k - 1] + f[k][r]

1 #include <bits/stdc++.h>
2
3 const int N = 510;
4
5 int f[N][N];
6 char str[N];
7
8 inline void exmin(int &a, const int &b) {
9 if(a > b) a = b;
10 return;
11 }
12
13 int main() {
14 memset(f, 0x3f, sizeof(f));
15 int n;
16 scanf("%d", &n);
17 scanf("%s", str + 1);
18 for(int i = 1; i <= n; i++) {
19 f[i][i] = 1;
20 }
21 for(int len = 2; len <= n; len++) {
22 for(int l = 1; l + len - 1 <= n; l++) {
23 int r = l + len - 1;
24 /// fa[l][r] fb[l][r] ans[l][r]
25 exmin(f[l][r], f[l + 1][r] + 1);
26 if(str[l] == str[l + 1]) {
27 exmin(f[l][r], f[l + 1][r]);
28 }
29 for(int k = l + 2; k <= r; k++) {
30 if(str[k] == str[l]) {
31 exmin(f[l][r], f[l + 1][k - 1] + f[k][r]);
32 }
33 }
34 }
35 }
36 printf("%d\n", f[1][n]);
37 return 0;
38 }
CF1132D Stressful Training
题意:有n个笔记本,一开始有ai格电,每分钟消耗bi格电。你要买一个每分钟充x格点的插头,使得这些笔记本都能撑过k分钟。问x的最小值。
解:不难想到二分。然后check里每天挑最早没电的充电。如果直接用堆的话是nlog2n的,然而我卡过去了...
实际上我们可以考虑把这些笔记本按照没电天来分类,发现同类笔记本我们不需要知道它们的相对大小,于是直接vector。然后从前往后扫一遍,就能做到线性。
注意二分上界是1e12...

1 #include <bits/stdc++.h>
2
3 typedef long long LL;
4 const int N = 200010;
5
6 inline char gc() {
7 static char buf[N], *p1(buf), *p2(buf);
8 if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, N, stdin);
9 return p1 == p2 ? EOF : *p1++;
10 }
11
12 template <class T> inline void read(T &x) {
13 x = 0;
14 register char c(gc());
15 bool f(false);
16 while(c < '0' || c > '9') {
17 if(c == '-') f = true;
18 c = gc();
19 }
20 while(c >= '0' && c <= '9') {
21 x = x * 10 + c - 48;
22 c = gc();
23 }
24 if(f) x = (~x) + 1;
25 return;
26 }
27
28 struct Node {
29 LL now, del;
30 double x;
31 Node(LL A = 0, LL B = 0) {
32 now = A;
33 del = B;
34 x = (double)A / B;
35 }
36 inline bool operator < (const Node &w) const {
37 return x > w.x;
38 }
39 }node[N];
40
41 int n, k;
42 LL a[N], b[N];
43 std::priority_queue<Node> Q;
44
45 inline bool check(LL x) {
46 while(Q.size()) Q.pop();
47 for(register int i = 1; i <= n; i++) {
48 Q.push(node[i]);
49 }
50 for(register int i = 0; i < k; i++) {
51 Node temp = Q.top();
52 Q.pop();
53 if(temp.now - temp.del * i < 0) {
54 return false;
55 }
56 temp = Node(temp.now + x, temp.del);
57 Q.push(temp);
58 }
59 Node temp = Q.top();
60 if(temp.now - temp.del * k < 0) {
61 return false;
62 }
63 return true;
64 }
65
66 int main() {
67
68 read(n); read(k);
69 k--;
70 for(register int i = 1; i <= n; i++) {
71 read(a[i]);
72 }
73 for(register int i = 1; i <= n; i++) {
74 read(b[i]);
75 }
76 for(register int i = 1; i <= n; i++) {
77 if(b[i] * k <= a[i]) {
78 std::swap(a[i], a[n]);
79 std::swap(b[i], b[n]);
80 n--;
81 i--;
82 }
83 }
84
85 if(!n) {
86 puts("0");
87 return 0;
88 }
89
90 for(int i = 1; i <= n; i++) {
91 node[i] = Node(a[i], b[i]);
92 }
93 std::sort(node + 1, node + n + 1);
94
95 LL l = 1, r = 2e12;
96 while(l < r) {
97 LL mid = (l + r) >> 1;
98 if(check(mid)) {
99 r = mid;
100 }
101 else l = mid + 1;
102 }
103 if(r == 2e12) puts("-1");
104 else {
105 printf("%lld\n", r);
106 }
107 return 0;
108 }
来源:https://www.cnblogs.com/huyufeifei/p/10618055.html
