ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NWERC2020 A - Atomic Energy (背包 + 思维)

2021-05-31 16:36:50  阅读:227  来源: 互联网

标签:NWERC2020 Energy define num 体积 dp 神经元 best Atomic


题意:
给你\(n\)个神经元,从\(1 - n\)编号,我们可以认为编号为\(i\)的神经元的体积为\(i\),带有\(a_i\)的能量。
然后一共有\(q\)个询问,每个询问带有一个\(k\),你需要回答,当一个体积为\(k\)的神经元分裂是会释放多少能量,能量释放按照以下规则:
一个体积为\(k\)的神经元,每次可以分解为两个体积分别为\(i,j\)的神经元,需要保证\(i + j = k\),当一个神经元体积\(v \leq n\)时,他将立即释放\(a_v\)的能量。每次询问,你需要回答能释放的最小的能量为多少。

思路:
首先,我们看,体积和能量,这两个参数是不是很像背包的问题。所以我们可以往这个方面考虑一下,但是这道题有点不同。
首先,我们分裂其实是有一个限制条件的,即不可能出现某个\(\leq n\)的数继续分裂,所以其实我们最后一定要留出两个体积\(v_1,v_2\)并且保证他们相加\(v_1 + v_2 > n\),至于剩余的体积\(K - v_1 - v_2\)就会有任意的分解方法,所以我们需要留出一个体积在\([n + 1,n * 2]\)的神经元来作分裂。

下一步再看,给定的\(K\)的范围,有点太大了也,肯定没法直接\(dp\),能不能把一个大范围贪心处理到一个小范围,我们考虑找到一个神经元使其"性价比"最好,即这个神经元体积尽量的大,同时能量尽量的小也就是\(\frac{a_i}{i}\)最小,其体积记为\(best\),则对于很大的\(k\)只需要让其减少若干的\(best\)掉入一个我们可接受的范围区间内,直接\(dp\)处理。

那这个区间的范围怎么确定呢,这里需要用到一个结论。
假如我现在有\(x\)个数,那么我从中选择若干个一定可以组成\(x\)的倍数。
证明来自b站某大佬视频:
既然是倍数,那么考虑这\(x\)个数都在模\(x\)意义下的取值,设\(s_i\)表示前\(i\)个数的前缀和在模\(x\)意义下的取值,很明显,\(x + 1\)个位置(什么不选即为0),模\(x\)最多有\(x\)个不同的取值,根据鸽巢原理(抽屉原理),那么一定会有两个位置\(i,j\)处的\(s_i = s_j\),即他们之间的数是\(x\)的倍数。

至此,我们可以知道,如果有超过\(\geq x\)个数,那么我们就可以选择其中若干个用\(best\)消去,直至总量\(< x\),所以我们需要预处理的范围其实就是[1,(best-1) * n],(best - 1)保证不会被消去,每个最大体积为\(n\),这样就可以通过\(O(n^3)\)的\(dp\)解决了。

这道题挺好的,有两个思维点,转换之后就是比较普通的背包了,值得积累,以后碰到范围很大的背包问题,可以考虑是否能缩小到一定范围内再去\(dp\),大范围直接贪心求解。

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const ll INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e6 + 10;
int n,q;
ll a[N],dp[N];

int main() {
	scanf("%d%d",&n,&q);
	int best;
	double mi = 1.0 * INF;//记录那个物品的性价比是最优的
	for(int i = 1;i <= n;i ++) {
		scanf("%lld",&a[i]);
		if(1.0 * a[i] / i < mi) {
			mi = 1.0 * a[i] / i;
			best = i;
		}
	}
	memset(dp,INF,sizeof(dp));
	for(int i = n + 1;i <= 2 * n;i ++) {
		for(int j = 1;j <= n;j ++) {
			if(i - j <= n) 
				dp[i] = min(dp[i],a[j] + a[i - j]);
		}
	}
	for(int i = n + 1;i <= n * (n + 1);i ++) {
		for(int j = 1;j <= n;j ++) {
			if(i - j > n) {
				dp[i] = min(dp[i],dp[i - j] + a[j]);
			}
		}
	}
	// for(int i = n + 1;i <= k;i ++) {
	// 	cout << dp[i] << '\n';
	// }
	ll k;
	while(q--) {
		scanf("%lld",&k);
		if(k <= n) {
			printf("%lld\n",a[k]);
		}
		else {
			if(k > n * (best + 1)) {//是值域落至可处理范围内 即k - j * best ∈ [1,(best-1)*n] (j = 1,2,...)
				ll num = (k - n * (best + 1) + best - 1) / best;
				ll ans = num * a[best] + dp[k - num * best];
				printf("%lld\n",ans);
			}
			else {
				printf("%lld\n",dp[k]);
			}
			// ll num = max(0LL,(k - n * (best + 1) + best - 1) / best);
			// ll ans = num * a[best] + dp[k - num * best];
			// printf("%lld\n",ans);
		}
	}
	return 0;
}

标签:NWERC2020,Energy,define,num,体积,dp,神经元,best,Atomic
来源: https://www.cnblogs.com/forward77/p/14831950.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有