首页 > 其他分享 >D. Trees and Segments

D. Trees and Segments

时间:2023-08-16 21:15:55浏览次数:39  
标签:beauty int text Segments Trees cdot 枚举 row

D. Trees and Segments

The teachers of the Summer Informatics School decided to plant $n$ trees in a row, and it was decided to plant only oaks and firs. To do this, they made a plan, which can be represented as a binary string $s$ of length $n$. If $s_i = 0$, then the $i$-th tree in the row should be an oak, and if $s_i = 1$, then the $i$-th tree in the row should be a fir.

The day of tree planting is tomorrow, and the day after tomorrow an inspector will come to the School. The inspector loves nature very much, and he will evaluate the beauty of the row as follows:

  • First, he will calculate $l_0$ as the maximum number of consecutive oaks in the row (the maximum substring consisting of zeros in the plan $s$). If there are no oaks in the row, then $l_0 = 0$.
  • Then, he will calculate $l_1$ as the maximum number of consecutive firs in the row (the maximum substring consisting of ones in the plan $s$). If there are no firs in the row, then $l_1 = 0$.
  • Finally, he will calculate the beauty of the row as $a \cdot l_0 + l_1$ for some $a$ — the inspector's favourite number.

The teachers know the value of the parameter $a$, but for security reasons they cannot tell it to you. They only told you that $a$ is an integer from $1$ to $n$.

Since the trees have not yet been planted, the teachers decided to change the type of no more than $k$ trees to the opposite (i.e., change $s_i$ from $0$ to $1$ or from $1$ to $0$ in the plan) in order to maximize the beauty of the row of trees according to the inspector.

For each integer $j$ from $1$ to $n$ answer the following question independently:

  • What is the maximum beauty of the row of trees that the teachers can achieve by changing the type of no more than $k$ trees if the inspector's favourite number $a$ is equal to $j$?

Input

The first line contains a single integer $t$ ($1 \le t \le 1000$) — the number of test cases.

The first line of each test case contains two integers $n$ and $k$ ($1 \le n \le 3000$, $0 \le k \le n$) — the number of trees in the row and the maximum number of changes.

The second line contains a string $s$ of length $n$, consisting of zeros and ones — the plan description.

It is guaranteed that the sum of all $n$ values for all test cases does not exceed $3000$.

Output

For each test case, print $n$ integers, the $j$-th ($1 \le j \le n$) of which is the maximum beauty of the row of trees after no more than $k$ changes if $a = j$ is used to calculate the beauty.

Example

input

5
3 0
111
4 1
0110
5 0
10000
6 2
101101
7 1
0001101

output

3 3 3 
4 5 7 9 
5 9 13 17 21 
6 9 13 17 21 25 
7 10 13 17 21 25 29 

Note

In the first test case no changes are allowed, so $l_0 = 0$ and $l_1 = 3$ always hold. Thus, regardless of the value of $a$, the beauty of the row of trees will be $3$.

In the second test case for $a \in \{1, 2\}$ the teachers can, for example, change the plan $s$ to $0111$ (by changing $s_4$), and for $a \in \{3, 4\}$ — to $0010$ (by changing $s_2$). In this case, the beauty of the row for each $a$ is calculated as follows:

  • For $a = 1$: $l_0 = 1$, $l_1 = 3$. The beauty of the row is $1\cdot 1 + 3 = 4$.
  • For $a = 2$: $l_0 = 1$, $l_1 = 3$. The beauty of the row is $2\cdot 1 + 3 = 5$.
  • For $a = 3$: $l_0 = 2$, $l_1 = 1$. The beauty of the row is $3\cdot 2 + 1 = 7$.
  • For $a = 4$: $l_0 = 2$, $l_1 = 1$. The beauty of the row is $4\cdot 2 + 1 = 9$.

It can be shown that the changes described above are optimal for all $a$ from $1$ to $4$.

 

解题思路

  题解有点看不懂,大概说一下我的做法吧。

  现在要求的是对于每个$a \in [1,n]$,$a \cdot l_0 + l_1$的最大值是多少,这取决于$l_0$和$l_1$分别是多少。可以知道当对字符串修改后,连续最长的一段$0$,和连续最长的一段$1$分别在左部分和右部分(或者是右部分和左部分),并且没有交集。

  而最长一段$0$的长度$l_0 \in [0,n]$,所以想到枚举最长一段$0$所有可能的长度,当$l_0$固定后枚举找到$l_1$最大能取多少。这样就能在修改之后连续最长的一段$0$是$l_0$的所有方案中,确定$l_1$的最大值,进而使得$a \cdot l_0 + l_1$最大(对于固定的$a$和$l_0$)。同理,最长一段$1$的长度$l_1 \in [0,n]$,同样枚举最长一段$1$所有可能的长度,当$l_1$固定后枚举找到$l_0$最大能取多少。

  最终就会得到最多$2n$个二元组$(l_0,l_1)$,这些二元组涵盖了所有能使得$a \cdot l_0 + l_1$取最大值的情况,接下来我们只需要枚举所有的$a$,固定$a$的值后再枚举所有的二元组,计算$a \cdot l_0 + l_1$取最大值,这一步的时间复杂度是$O(n^2)$。

  上面就是大致的思路,下面给出具体做法,这里只给出枚举$l_0$分别找到最大$l_1$的方法,另外的枚举$l_1$分别找到最大$l_0$的做法也是类似的,只需把字符串中的$0$变成$1$,$1$变成$0$,然后用同样的方法即可。

  先枚举最长一段$0$的长度$\text{len}$,然后在字符串中找到所有长度为$\text{len}$的连续子串,来作为最长的一段$0$。因此需要先判定能否将该子串全部变成$0$,即子串中$1$的个数$\text{cnt}$是否不超过$k$。如果$\text{cnt} > k$那么我们就无法通过不超过$k$步的修改使得整个子串变成$0$。否则$\text{cnt} \leq k$,假设子串的左右端点为$l$和$r$,满足$r-l+1=\text{len}$,那么我们就看看字符串$[1,l-1]$及$[r+1,n]$中连续最长的$1$是多少,记作$t$。最后枚举完所有长度为$\text{len}$的子串,把最大的那个$t$作为$l_1$。

  上面做法的伪代码如下:

 1 for (int len = 0; len <= n; len++) {    // 枚举连续最长的0的长度
 2     int l1 = -1;
 3     for (int l = 1; l + len - 1 <= n; l++) {    // 枚举所有长度为len的子串左端点l
 4         int r = l + len - 1;    // 子串右端点r
 5         int cnt = 0;
 6         for (int i = l; i <= r; i++) {
 7             if (str[i] == '1') cnt++;    // 统计子串中1的个数
 8         }
 9         if (cnt > k) continue;    // 1的个数超过k,无法把子串修改为全0,枚举下一个子串
10         int s = k = cnt;    // 剩余能修改的次数
11         int t = 0;
12         // 找到[1,l-1]中连续最长的一段1
13         for (int i = 1; i < l; i++) {
14             for (int j = 0; j <= s; j++) {
15                 if (str[i] == '1') f[i][j] = f[i - 1][j] + 1;
16                 else if (j) f[i][j] = f[i - 1][j - 1] + 1;
17                 else f[i][j] = 0;
18             }
19             t = max(t, f[i][s]);
20         }
21         // 找到[r+1,n]中连续最长的一段1
22         for (int i = n; i > r; i--) {
23             for (int j = 0; j <= s; j++) {
24                 if (str[i] == '1') g[i][j] = g[i + 1][j] + 1;
25                 else if (j) g[i][j] = g[i + 1][j - 1] + 1;
26                 else g[i][j] = 0;
27             }
28             t = max(t, f[i][s]);
29         }
30         l1 = max(l1, t);
31     }
32     if (l1 != -1) p.push_back({len, l1});    // l1==-1说明字符串中不存在长度为len的连续一段0
33 }

  可以看到时间复杂度是$O(n^4)$。其中上面代码中找到$[1,l-1]$和$[r+1,n]$中连续最长的一段$1$用到了动态规划。

  实际上上面的做法是可以通过预处理优化到$O(n^2)$的,首先求子串中$1$的个数可以用前缀和优化到$O(1)$,找到$[1,l-1]$和$[r+1,n]$中连续最长的一段$1$也可以通过动态规划预处理所有的情况来优化到$O(1)$。

  先定义状态$h(i,j)$表示前缀中以第$i$个字符作为连续最长一段$1$的右端点,且最多修改$j$次得到的最大长度。状态转移方程为$$h(i,j) = \left\{ \begin{array}{c}  h(i-1, j) + 1 & \text{if} & \text{str}_i = 0 \\ h(i-1, j-1) + 1 & \text{if} & \text{str}_i = 1 & \text{and} & j > 0 \\ 0 & \text{otherwise} \end{array}\right.$$

  再定义状态$f(i,j)$表示只考虑前$i$个字符,且最多修改$j$次得到的所有方案中,连续一段$1$的最大长度。根据第$i$个字符是否在最长的连续一段$1$中进行状态划分,因此状态转移方程就是$$f(i,j) = \max\left\{ f(i-1,j), h(i,j) \right\}$$

  这样对于任意的前缀$[1,l]$以及最多能修改的次数$k'$,就能通过查询$f(l,k')$来得到。

  同理定义状态$h'(i,j)$表示后缀中以第$i$个字符作为连续最长一段$1$的左端点,且最多修改$j$次得到的最大长度。状态转移方程为$$h'(i,j) = \left\{ \begin{array}{c} h'(i+1, j) + 1 & \text{if} & \text{str}_i = 0 \\ h'(i+1, j-1) + 1 & \text{if} & \text{str}_i = 1 & \text{and} & j > 0 \\ 0 & \text{otherwise} \end{array}\right.$$

  再定义状态$g(i,j)$表示只考虑$[i,n]$中的字符,且最多修改$j$次得到的所有方案中,连续一段$1$的最大长度。根据第$i$个字符是否在最长的连续一段$1$中进行状态划分,因此状态转移方程就是$$g(i,j) = \max\left\{ g(i+1,j), h'(i,j) \right\}$$

  这样对于任意的前缀$[r,n]$以及最多能修改的次数$k'$,就能通过查询$g(r,k')$来得到。

  上面dp的时间复杂度是$O(n \cdot k)$。

  AC代码如下,时间复杂度为$O(n \cdot k + n^2)$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 3010;
 5 
 6 int n, m;
 7 char str[N];
 8 int s[N];
 9 int f[N][N], g[N][N], h[N][N];
10 vector<vector<int>> p;
11 
12 void get(int op) {
13     if (op) {
14         for (int i = 1; i <= n; i++) {
15             str[i] ^= 1;
16         }
17     }
18     for (int i = 1; i <= n; i++) {
19         s[i] = s[i - 1];
20         if (str[i] == '1') s[i]++;
21     }
22     for (int i = 0; i <= n + 1; i++) {
23         for (int j = 0; j <= m; j++) {
24             f[i][j] = g[i][j] = h[i][j] = 0;
25         }
26     }
27     for (int i = 1; i <= n; i++) {
28         for (int j = 0; j <= m; j++) {
29             if (str[i] == '1') h[i][j] = h[i - 1][j] + 1;
30             else if (j) h[i][j] = h[i - 1][j - 1] + 1;
31             else h[i][j] = 0;
32             f[i][j] = max(f[i - 1][j], h[i][j]);
33         }
34     }
35     for (int i = n; i; i--) {
36         for (int j = 0; j <= m; j++) {
37             if (str[i] == '1') h[i][j] = h[i + 1][j] + 1;
38             else if (j) h[i][j] = h[i + 1][j - 1] + 1;
39             else h[i][j] = 0;
40             g[i][j] = max(g[i + 1][j], h[i][j]);
41         }
42     }
43     for (int len = 0; len <= n; len++) {
44         int t = -1;
45         for (int i = 1; i + len - 1 <= n; i++) {
46             int j = i + len - 1, cnt = s[j] - s[i - 1];
47             if (cnt <= m) t = max({t, f[i - 1][m - cnt], g[j + 1][m - cnt]});
48         }
49         if (t == -1) break;
50         if (!op) p.push_back({len, t});
51         else p.push_back({t, len});
52     }
53 }
54 
55 void solve() {
56     scanf("%d %d %s", &n, &m, str + 1);
57     p.clear();
58     get(0), get(1);
59     for (int i = 1; i <= n; i++) {
60         int ret = 0;
61         for (auto &q : p) {
62             ret = max(ret, i * q[0] + q[1]);
63         }
64         printf("%d ", ret);
65     }
66     printf("\n");
67 }
68 
69 int main() {
70     int t;
71     scanf("%d", &t);
72     while (t--) {
73         solve();
74     }
75     
76     return 0;
77 }

 

参考资料

  Codeforces Round #893 (Div. 2) Editorial:Codeforces Round #893 (Div. 2) Editorial - Codeforces

标签:beauty,int,text,Segments,Trees,cdot,枚举,row
From: https://www.cnblogs.com/onlyblues/p/17636147.html

相关文章

  • vue-treeselect 校验失败添加红框
    需求vue-treeselect校验及清除校验这篇介绍了用@input在校验失败时显示校验信息。但还需要同时显示红色边框。如下图所示:解决办法思路:动态绑定类名,校验失败时切换类名,更改边框颜色。子组件SelectTree二次封装vue-treeselect:组件SelectTree<template><divclass=......
  • LeetCode 7022——熟悉TreeSet数据结构及常用方法的使用
    LeetCode7022.限制条件下元素之间的最小绝对差题目描述:给你一个下标从 0 开始的整数数组 nums 和一个整数 x 。请你找到数组中下标距离至少为 x 的两个元素的 差值绝对值 的 最小值 。换言之,请你找到两个下标 i 和 j ,满足 abs(i-j)>=x 且 abs(nums[i......
  • Paper Reading: NBDT: Neural-Backed Decision Trees
    目录研究动机文章贡献本文方法推理建立层次结构用WordNet标记决策节点微调和树监督损失实验结果对比实验结果可解释性识别错误的模型预测引导图像分类人更倾向的解释识别有缺陷的数据标签优点和创新点PaperReading是从个人角度进行的一些总结分享,受到个人关注点的侧重和实力......
  • 全局引用ant-design-vue的TreeSelect没有样式
    在全局只按需引用了TreeSelect---vue.use(TreeSelect)没有样式.........需要在babel.config.js里的plugins配置plugins:[["import",{"libraryName":"ant-design-vue",//库名称"libraryDirectory"......
  • [LeetCode] 894. All Possible Full Binary Trees
    Givenaninteger n,return alistofallpossible fullbinarytrees with n nodes.Eachnodeofeachtreeintheanswermusthave Node.val==0.Eachelementoftheansweristherootnodeofonepossibletree.Youmayreturnthefinallistoftreesin......
  • CF633G Yash And Trees
    简单题。先把树拍扁成序列,在dfn序上区间修改区间查询。由于时限4s,我们可以整点怪的,比如bitset。把区间内的数有/没有表示成\(01\)序列,考虑到区间加取模相当于区间内的数全部循环右移,用bitset可以做到\(O(\fracm\omega)\)。然后用线段树维护这个序列就行了,查询的时......
  • CF997E Good Subsegments
    简单题,不知道为啥和弱化版一个Difficulty。考虑弱化怎么做。区间\([l,r]\)中的数是连续的,当且仅当区间最大值\(\max\)减去区间最小值\(\min\)为\(r-l\),即\(\max-\min=r-l\)。考虑扫描线,固定右端点\(r\),统计每个左端点的贡献。由于\(S(l,r)=\text{max}-\text{min}+l......
  • 1843E - Tracking Segments
    Problem-E-Codeforces题意是现在有n个0,给你m段序列,然后给你q次操作,每次操作给一个x,把第x个0变成1,问你最少几次操作能出现一段序列里的1的数量大于0的数量,如果不存在,输出-1对于操作数是一个递增序列。如果第k次操作后正好可行,那么就不用管k+1及以后了。所以可以使用二分来解......
  • vue-treeselect 被 overflow 遮挡
    场景在一个内容区域设置了overflow纵向滚动的对话框中,内部的vue-treeselect组件下拉框选项被遮挡了。解决办法给vue-treeselect设置appendToBody和z-index属性。注意事项设置了appendToBody后,下拉框选项的字号会变大。为了与原来的字号相匹配,需要修改样式。找......
  • CF1843E Tracking Segments
    CF1843ETrackingSegmentsVP的时候本来摆烂了,结果快结束的时候想到了做法(没时间敲了qwq)。这里提供一种和已有题解不同的思路。我们发现,对于每个修改,我们可以将该点的值修改为这次修改的时间,未修改的点则赋为\(n+1\)。这样转化后,区间合法的条件就是区间内小于\(n+1\)的值至......