其他分享
首页 > 其他分享> > [USACO18DEC]Teamwork G 题解

[USACO18DEC]Teamwork G 题解

作者:互联网

题目描述

在 Farmer John 最喜欢的节日里,他想要给他的朋友们赠送一些礼物。由于他并不擅长包装礼物,他想要获得他的奶牛们的帮助。你可能能够想到,奶牛们本身也不是很擅长包装礼物,而 Farmer John 即将得到这一教训。

Farmer John 的 \(N\) 头奶牛(\(1\le N\le 10^4\))排成一行,方便起见依次编号为 \(1\dots N\)。奶牛 \(i\) 的包装礼物的技能水平为 \(s_i\)。她们的技能水平可能参差不齐,所以 FJ 决定把她的奶牛们分成小组。每一组可以包含任意不超过 \(K\) 头的连续的奶牛(\(1\le K\le 10^3\)),并且一头奶牛不能属于多于一个小组。由于奶牛们会互相学习,这一组中每一头奶牛的技能水平会变成这一组中水平最高的奶牛的技能水平。

请帮助 FJ 求出,在他合理地安排分组的情况下,可以达到的技能水平之和的最大值。

输入格式

输入的第一行包含 \(N\) 和 \(K\)。以下 \(N\) 行按照 \(N\) 头奶牛的排列顺序依次给出她们的技能水平。技能水平是一个不超过 \(10^5\) 的正整数。

输出格式

输出 FJ 通过将连续的奶牛进行分组可以达到的最大技能水平和。

样例输入

7 3
1
15
7
9
2
5
10

样例输出

84

十分有意思的一道题,首先根据套路 状态表达 \(dp[i]\) 表示前 \(i\) 头奶牛的最大技能水平和,则有方程 \(dp[i]=max(dp[i],dp[j]+max\) \(j=\sum_{i-k}^i w_j)\) 。

难点来到了如何快速求出区间最大值,解决方法多种多样,例如 \(ST\)表,线段树等,这里写了树状数组,因为题目给的 \(N\) 并不大,可以轻松处理,时间复杂度 \(O(nk\log^2n)\) ,若使用 \(ST\) 表可将复杂度降为 \(O(nk)\) 。

Code.

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,k,w[N],tr[N],f[N];
int lowbit(int x) {return x&-x;}
void modify()
{
	for(int i=1;i<=n;i++)
		for(int j=i-lowbit(i)+1;j<=i;j++)
			tr[i]=max(tr[i],w[j]);
}
int query(int l,int r)
{
	int res=0;
	while(r>=l)
	{
		res=max(res,w[r--]);
		for(;r-lowbit(r)>=l;r-=lowbit(r)) 
			res=max(res,tr[r]);
	}
	return res;
}
signed main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	modify();
	for(int i=1;i<=n;i++)
	{
		if(i-k < 1) {f[i]=query(1,i) * i; continue;}
		else for(int j=i-k;j < i;j++) f[i]=max(f[i],f[j]+query(j+1,i)*(i-j));
	}
	printf("%d",f[n]);
	return 0;
}

标签:10,int,题解,水平,Teamwork,res,USACO18DEC,奶牛,技能
来源: https://www.cnblogs.com/EastPorridge/p/16369369.html