cf935:D.Seraphim the Owl(贪心)

题目

大家排成 𝑛n 队,从 𝑖=1i=1 号开始,向猫头鹰谢拉菲姆请教生命的意义。不巧的是,基里尔正忙着为这个问题编写传说,所以他来得晚了一些,站在了 𝑛n 这个人之后,排在了队伍的最后。基里尔对这种情况完全不满意,于是他决定贿赂一些排在他前面的人。

对于队列中的 𝑖i /第三个人,基里尔知道两个值: 𝑎𝑖ai 和 𝑎𝑖ai : 𝑎𝑖ai 和 𝑏𝑖bi 。如果此刻基里尔站在 𝑖i 位置,那么他可以选择 𝑗j 这样的任意位置 𝑗<𝑖j<i ,与 𝑗j 位置的人交换位置。在这种情况下,基里尔需要支付他 𝑎𝑗aj 个金币。而对于 𝑘k 中的每一个 𝑗<𝑘<𝑖j<k<i ,基里尔都要向位置 𝑘k 的人支付 𝑏𝑘bk 个硬币。基里尔可以任意多次执行此操作。

基里尔很节俭,所以他想花尽可能少的硬币,但是他又不想等太久,所以基里尔认为他应该排在 𝑚m 人的前面。

请帮助基里尔确定,为了不等太久,他最少需要花费多少硬币。

输入

每个测试由几组输入数据组成。第一行包含一个整数 𝑡t ( 1≤𝑡≤1041≤t≤104 ) - 测试用例的数量。然后是测试用例的描述。

每个测试用例的第一行包含两个整数 𝑛n 和 𝑚m ( 1≤𝑚≤𝑛≤2000001≤m≤n≤200000 ) --分别是除基里尔之外的队列人数和基里尔最终位置的最大允许值。

第二行包含 𝑛n 个整数 𝑎1,𝑎2,…,𝑎𝑛a1,a2,…,an ,用空格分隔( 1≤𝑎𝑖≤1091≤ai≤109 )。

第三行包含 𝑛n 个整数 𝑏1,𝑏2,…,𝑏𝑛b1,b2,…,bn ,用空格隔开( 1≤𝑏𝑖≤1091≤bi≤109 )。

保证所有测试用例中 𝑛n 的值之和不超过 2⋅1052⋅105 。

输出

对于每个测试用例,输出一个整数 - Kirill 需要花费的最少金币数

做法

我们要走到前m个人以内,那么后面的人我们不管他怎么插队,反正每个人要么给他ai个金币,要么给他bi个金币,我们就选小的给就好了。然后到了前m个人的话,最终选择的位置必须给那个人ai个金币。

#include<bits/stdc++.h>
using namespace std;
int t,n,m;

struct ty{
	long long a,b;
};

long long qzh[200010];

int main(){

	scanf("%d",&t);

	while(t--){

		scanf("%d%d",&n,&m);
		vector<ty> v(n+1);
		

		for(int i=1;i<=n;i++){
			scanf("%lld",&v[i].a);
		}
		for(int i=1;i<=n;i++){
			scanf("%lld",&v[i].b);
		}
		
		for(int i=1;i<=n/2;i++){//倒序好处理一点
			swap(v[i],v[n+1-i]);
		}
		
		for(int i=1;i<=n;i++){
			qzh[i]=qzh[i-1]+min(v[i].a,v[i].b);
		}
		
		
		long long minn=0x3f3f3f3f3f3f3f3f;
		for(int i=n-m+1;i<=n;i++){
			
			minn=min(qzh[i-1]+v[i].a,minn);
			
		}
		cout<<minn<<endl;
		
	}
}

最近在学dp嘛,感觉能用dp写,但复杂度降不下去,加上题目那的标记也说是动规,我还以为是哪里可以降低复杂度,没想到是贪心了。dp的话就要考虑是从哪个位置插队上来的最小,但其实根本就不用这么复杂。

#include<bits/stdc++.h>
using namespace std;
int t,n,m;
long long dp[200010];//考虑了前i个位置,最小金币为 
struct ty{
	long long a,b;
};
long long qzh[200010];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		vector<ty> v(n+1);
		

		for(int i=1;i<=n;i++){
			scanf("%lld",&v[i].a);
		}
		for(int i=1;i<=n;i++){
			scanf("%lld",&v[i].b);
		}
		
		for(int i=1;i<=n/2;i++){
			swap(v[i],v[n+1-i]);
		}
		
		for(int i=1;i<=n;i++){
			qzh[i]=qzh[i-1]+v[i].b;
		}
		
		memset(dp,0x3f3f3f3f3f3f3f3f,sizeof(dp));
		dp[0]=0;
		for(int i=1;i<=n;i++){
			for(int j=0;j<i;j++){
				dp[i]=min(dp[i],dp[j]+v[i].a+qzh[i-1]-qzh[j]);
			}
			

		}
		
		long long minn=0x3f3f3f3f3f3f3f3f;
		for(int i=n-m+1;i<=n;i++) minn=min(dp[i],minn);
		cout<<minn<<endl;
		
	}
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值