D. Trees and Segments

l0:最大连续0的个数,l1:最大连续1的个数

题目要求a*l0+l1的值最大

可以翻转k次操作

我们知道最大的连续0和最大连续1之间一定会有间隔

比如:0111111010000000000

前7位最大连续1的个数位6个,你的最大连续0的个数就一定要在第8位后面去找

于是我们可以用一个dp函数去找

dp[i][j]表示前i位翻转j次出现连续最大1的最大次数

dp2[i][j]表示后i位翻转j次出现连续0的最大次数

于是我们就可以知道当你要求前i位翻转j(j<=k)次时最大1的次数,你要找到最大0的次数就是在dp2[m-i][k-j]就是后m-i位翻转k-j次最大0的次数

然后再做一遍dp

dp[i][j]表示前i位翻转j次     最大0的次数

dp2[i][j]表示后i位翻转j次   最大1的次数

根据上面再做一遍

如果你开一个best[i]表示当你l1取i时你l0最大是多少,当然越大越好

#include<iostream>
#include<algorithm>
#include<numeric>//accumulate(be,en,0)
#include<cstring>//rfind("string"),s.find(string,begin)!=s.npos,find_first _of(),find_last_of()
#include<string>//to_string(value),s.substr(int begin, int length);
#include<cstdio>
#include<cmath>
#include<vector>//res.erase(unique(res.begin(), res.end()), res.end()),reverse(q.begin(),q.end()),vector<int>().swap(at[mx])
#include<queue>//priority_queue(big)  /priority_queue<int, vector<int>, greater<int>> q(small)
#include<stack>
//#include<map>//unordered_map
#include<set>//iterator,insert(),erase(),lower(>=)/upper_bound(>)(value)/find()return end()
#include<unordered_map>
#include<unordered_set>
#include<bitset>//size,count(size of 1),reset(to 0),any(have 1?)
//#include<ext/pb_ds/assoc_container.hpp>//gp_hash_table
//#include<ext/pb_ds/hash_policy.hpp>
//using namespace __gnu_pbds;
#define int long long//__int128 2^127-1(GCC)
#define PII pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 5, mod = 1e9 + 7;
vector<vector<int>>calc(string& s, char c)
{
	int n = s.size();
	vector<vector<int>>ans;
	vector<int>cur(n + 1, 0);
	vector<int>pos;
	pos.emplace_back(-1);
	for (int i = 0; i < n; i++) {
		ans.emplace_back(cur);
		if (s[i] == c) pos.emplace_back(i);
		int m = pos.size();
		for(int j = 0; j < m; j++) {
			cur[m - j - 1] = max(cur[m - j - 1], i - pos[j]);
		}
		for (int i = 1; i <= n; i++) cur[i] = max(cur[i], cur[i - 1]);
	}
	ans.emplace_back(cur);
	return ans;
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		int n, k;
		cin >> n >> k;
		string s;
		cin >> s;
		vector<int>best(n + 1, -100000);
		for (int z : {0, 1}) {
			vector<vector<int>>dp = calc(s, '0');
			reverse(s.begin(), s.end());
			vector<vector<int>>dp2 = calc(s, '1');
			reverse(dp2.begin(), dp2.end());
			for (int i = 0; i <= n; i++) {
				for (int j = 0; j <= k; j++) {
					best[dp[i][j]] = max(best[dp[i][j]], dp2[i][k - j]);
				}
			}
		}
		for (int i = 1; i <= n; i++) {
			int ans = 0;
			for (int j = 0; j <= n; j++) {
				ans = max(ans, i * best[j] + j);
			}
			cout << ans << ' ';
		}
		cout << '\n';
	}
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值