CF集萃1

因为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
");
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
", ans);
41     return 0;
42 }
AC代码

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 
", 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 
", 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
", ans);
101         memset(str1 + 1, 0, n * sizeof(char));
102     }
103 
104     return 0;
105 }
AC代码

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
", 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
", 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
", ans);
130     return 0;
131 }
AC代码

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 
", l, r, fa[l][r], fb[l][r], ans[l][r]);
53         }
54     }
55     printf("%d
", ans[1][n]);
56     return 0;
57 }
AC代码

然而本题还有多种简单一点的方法......

就设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
", f[1][n]);
37     return 0;
38 }
AC代码

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
", r);
106     }
107     return 0;
108 }
AC代码
原文地址:https://www.cnblogs.com/huyufeifei/p/10618055.html