ICode9

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

ARC100 部分题解

2022-09-16 18:04:10  阅读:232  来源: 互联网

标签:include 题解 mid ARC100 sr sl now 部分 define


C:
转化一下就是取中间部位,绝对值之和最小

// by Balloons
#include <cstdio>
#include <vector>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;

int n,a[maxn];

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]), a[i] -= i;
	sort(a+1, a+n+1);
	if(n == 1)return puts("0"), 0;
	int tmp = n/2, tmp2 = n/2+1;
	LL res1=0, res2=0;
	tmp = a[tmp], tmp2 = a[tmp2];
	for(int i=1;i<=n;i++)res1 += abs(a[i] - tmp);
	for(int i=1;i<=n;i++)res2 += abs(a[i] - tmp2);
	printf("%lld\n",min(res1, res2));

	return 0;
}


D
枚举中间的断点,感受一下可以发现答案最小则一定两边的答案最小
二分两边的差,再二分求出对应的第一、三个断点的位置来判断是否存在,2个log

// by Balloons
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;
#define int LL

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;

int n,a[maxn], sum[maxn]; 

int getsum(int l,int r){return sum[r] - sum[l-1];}

int check(int x,int lim){
	int s1 = getsum(1, x);
	int l = 1, r = x, lf1, lf2;
	while(l <= r){
		int mid = l+r>>1;
		if(getsum(mid, r) >= (s1 - lim)/2)lf1 = mid, l = mid+1;
		else r = mid-1;
	}
	l = 1, r = x;
	while(l <= r){
		int mid = l+r>>1;
		if(getsum(mid, r) <= (s1 + lim)/2)lf2 = mid, r = mid-1;
		else l = mid+1;
	}
	if(lf1 > lf2)return 0;
	
	debug();
	
	int s2 = getsum(x+1, n);
	l = x+1, r = n;
	int ri1, ri2;
	while(l <= r){
		int mid = l+r>>1;
		if(getsum(mid, n) >= (s2 - lim)/2)ri1 = mid, l = mid+1;
		else r = mid-1;
	}
	l = x+1, r = n;
	while(l <= r){
		int mid = l+r>>1;
		if(getsum(mid, n) <= (s2 + lim)/2)ri2 = mid, r = mid-1;
		else l = mid+1;
	}
	if(ri1 > ri2)return 0;
	return 1;
}

signed main(){
	cin >> n;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)sum[i] = sum[i-1] + a[i];
	int r = 1e15;
	printf("%d\n",check(2,2));
	for(int i = 2;i<=n-2;i++){
		int l = 0, r = 1e15, ans;
		while(l <= r){
			int mid = l+r>>1;
			if(check(i, mid))r = mid-1, ans = mid;
			else l = mid+1;
		}
		r = min(r, ans);
	}
	cout << r << endl;

	return 0;
}

注意到随着中间断点往右挪,第一个断点肯定是不断往右的,因此我们就有了一个\(O(n)\)的算法
我这里面的p1[i]表示中间断点在(i,i+1)之间,左边的最小/大值,p2[i]同理

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;
#define int LL

const int inf = 1e9, INF = 0x3f3f3f3f, maxn= 2e5 + 5;

int n;
int a[maxn];
pair<int,int>p1[maxn], p2[maxn];

signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	
	int now = 1;
	LL sl = a[1], sr = a[2];
	p1[2] = mpr(sl, sr);
	for(int i=3;i<=n-2;i++){	// sl = a[1..now] sr = a[now+1..i]
		sr += a[i];
		while(now+1 < i && abs(sl - sr) > abs(sl + a[now+1] - (sr - a[now+1])))
			sl += a[now+1], sr -= a[now+1], ++ now;
		p1[i] = mpr(sl, sr);
	}
	now = n;
	sl = a[n-1], sr = a[n];
	p2[n-2] = mpr(sl, sr);
	for(int i = n-2;i>=3;i--){
		sl += a[i];
		while(now-1 > i && abs(sl - sr) > abs(sl - a[now-1] - (sr + a[now-1])))
			sl -= a[now-1], sr += a[now-1], -- now;
		p2[i-1] = mpr(sl, sr);
	}
	
	int ans = 2e9;
	for(int i=2;i<=n-2;i++){
		int tt[] = {p1[i].first, p1[i].second, p2[i].first, p2[i].second};
		sort(tt, tt+4);
		ans = min(ans, tt[3] - tt[0]);
	}
	printf("%lld\n",ans);

	return 0;
}

E
把下标\(x\)看成一个二进制集合
\(i|j \leq k\)一看就很前缀max
但是因为\(i | j \leq k\)不好处理,做一步转化:
只需要考虑\(i | j \in k\)的情况,做一个前缀max即可,显然这也是对的
考虑什么样的\(i, j\),k能被更新?显然是k为i和j的超集的时候,这显然是高维前缀和的经典应用(\(S \ xor\ (1<<k)==0\)的时候更新答案)
维护答案就记录一个最大值和次大值即可

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n;
int a[(1<< 18) + 5];
int mx[(1<< 18) + 5][2];

void ck(int x,int y){
	int pp[] = {mx[x][0], mx[x][1], mx[y][0], mx[y][1]};
	sort(pp,pp+4);
	mx[x][0] = pp[3], mx[x][1] = pp[2];
}

signed main(){
	scanf("%d",&n);
	for(int i=0;i<=(1<<n) - 1;i++)scanf("%d",&a[i]), mx[i][0] = a[i], mx[i][1] = 0;
	for(int k = 0;k<=n-1;k++)
		for(int S = 0;S<=(1<<n)-1;S++)
			if((S & (1<<k)) == 0){
				ck(S ^ (1<<k), S);
			}
	int res = 0;
	for(int i=1;i<=(1<<n) - 1;i++){
		res = max(res, mx[i][0] + mx[i][1]);
		printf("%d\n",res);
	}

	return 0;
}

标签:include,题解,mid,ARC100,sr,sl,now,部分,define
来源: https://www.cnblogs.com/SkyRainWind/p/16700739.html

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

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

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

ICode9版权所有