计蒜客 2020 蓝桥杯省赛 B 组模拟赛(五)程序设计:序列划分

  •  1000ms
  •  262144K

给定一个长度为 nn 的序列 aa,以及一个整数 cc。

一个长度为 kk 的序列的值为序列中除了最小的 \lfloor \frac k c \rfloor⌊ck​⌋ 个元素之外的所有元素之和。

例如 c = 2c=2,[3,1,6,5,2][3,1,6,5,2] 的值为 3+6+5=143+6+5=14。

现在你需要将数组 aa 划分成若干个连续的子序列,求所有划分方案中子序列的值之和的最小值。

输入格式

第一行两个整数 n, cn,c。

第二行 nn 个整数,表示序列 aa。

输出格式

输出一行一个整数,表示所有划分方案中子序列值之和的最小值。

数据范围

对于 40\%40% 的数据,1 \leq n, c \leq 10^31≤n,c≤103

对于 100\%100% 的数据,1 \leq n, c \leq 10^51≤n,c≤105

对于 100\%100% 的数据,1 \leq a[i] \leq 10^91≤a[i]≤109

样例输入复制

12 10
1 1 10 10 10 10 10 10 9 10 10 10

样例输出复制

92

思路:

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int lg[N] = {-1};
int minn[N][20];
int data[N];
long long dp[N];
long long sum[N];

int _pow(int a)
{
	return 1 << a;
}

int query(int l, int r)//可以有重复区间
{
	int len = lg[r-l+1];
	int a = minn[l][len];
	int b = minn[r-_pow(len)+1][len];
	return data[a] < data[b] ? data[a] : data[b];
}

int main()
{
	int n,c;
	cin>>n>>c;
	
	for(int i=1; i<=n; i++)
	{
		scanf("%d", &data[i]);
		sum[i] = sum[i-1] + data[i];
		lg[i] = lg[i/2] + 1;
		minn[i][0] = i;
	}
	
	for(int j=1; _pow(j)<=n; j++)
		for(int i=1; i+_pow(j)-1<=n; i++)
		{
			int a = minn[i][j-1];
			int b = minn[i+_pow(j-1)][j-1];
			minn[i][j] = data[a] < data[b] ? a : b;
		}
	
	for(int i=1; i<=n; i++)
	{
		if(i < c) dp[i] = sum[i];
		else
		{
			dp[i] = min(dp[i-1] + data[i], dp[i-c] + sum[i] - sum[i-c] - query(i - c + 1, i));
		} 
	}
	cout<<dp[n];
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值