AtCoder Regular Contest 100 (ARC100) D - Equal Cut 二分

原文链接https://www.cnblogs.com/zhouzhendong/p/9251420.html

题目传送门 - ARC100D

题意

  给你一个长度为 $n$ 的数列,请切 $3$ 刀,形成 $4$ 个连续非空子序列,问这 $4$ 个非空子序列的各自的元素和 的极差为多少。

  $n\leq 2\times 10 ^5$

题解

  如果切一刀,那么问题就很简单,尽量选中间的就可以了。

  可以二分一下在 $O(\log n)$ 的复杂度内解决。

  于是本题可以先枚举一下中间那条线,然后对于两边转化成刚才的子问题。

  然而!

  关键是:我居然没有想到,大概是脑抽了吧。

  然而!

  我通过乱搞过掉了!!

  本题第一次让我感受到了乱搞的强大!!

代码

  正解我没写过。这里放乱搞,仅供观看,别喷谢谢。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005;
int n;
LL a[N],sum[N],v;
int x[5]={0};
LL calc(int i){
	return sum[x[i]]-sum[x[i-1]];
}
LL llabs(LL x){
	return x<0?-x:x;
}
bool cmp(int a,int b){
	return calc(a)<calc(b);
}
bool cmp2(int a,int b){
	return calc(a)>calc(b);
}
void move(int id,int d){
	if (d==1){
		if (x[id+1]-x[id]>1)
			x[id]++;
	}
	else {
		if (x[id]-x[id-1]>1)
			x[id]--;
	}
}
LL trys(){
	LL ans=1e17;
	int y[5];
	for (int i=0;i<5;i++)
		y[i]=x[i];
	for (int i=1;i<=20;i++){
		int id[5]={0,1,2,3,4};
		sort(id+1,id+5,cmp);
		ans=min(ans,llabs(calc(id[1])-calc(id[4])));
		int r=rand()%6;
		if (r==0){
			LL val=calc(1);
			if (val>v)
				move(1,-1);
			else
				move(1,1);
		}
		if (r==1){
			LL val=calc(4);
			if (val>v)
				move(3,1);
			else
				move(3,-1);
		}
		if (r>1){
			r-=2;
			int k=r&1?2:3;
			r/=2;
			LL val=calc(k);
			if (r){
				if (val>v)
					move(k-1,1);
				else
					move(k-1,-1);
			}
			else {
				if (val>v)
					move(k,-1);
				else
					move(k,1);
			}
		}
	}
	for (int i=0;i<5;i++)
		x[i]=y[i];
	return ans;
}
LL solve(){
	for (int i=1;i<=n;i++)
		sum[i]=sum[i-1]+a[i];
	v=sum[n]/4;
	for (int i=1;i<=3;i++){
		x[i]=x[i-1]+1;
		while (x[i]<n+i-4&&sum[x[i]]-sum[x[i-1]]<=v)
			x[i]++;
	}
	x[4]=n;
	LL ans=1e17;
	for (int xxxx=1;xxxx<=n*4;xxxx++){
		ans=min(ans,trys());
		int id[5]={0,1,2,3,4};
		sort(id+1,id+5,cmp);
		ans=min(ans,llabs(calc(id[1])-calc(id[4])));
		int j=1;
		while (j<=4&&(id[j]==1||x[id[j]-1]-x[id[j]-2]==1))
			j++;
		if (j>4)
			break;
		x[id[j]-1]--;
	}
	return ans;
}
LL solve2(){
	for (int i=1;i<=n;i++)
		sum[i]=sum[i-1]+a[i];
	v=sum[n]/4;
	for (int i=1;i<=3;i++){
		x[i]=x[i-1]+1;
		while (x[i]<n+i-4&&sum[x[i+1]]-sum[x[i]]<=v)
			x[i]++;
	}
	x[4]=n;
	LL ans=1e17;
	for (int xxxx=1;xxxx<=n*4;xxxx++){
		int id[5]={0,1,2,3,4};
		sort(id+1,id+5,cmp2);
		ans=min(ans,llabs(calc(id[1])-calc(id[4])));
		int j=1;
		while (j<=4&&(id[j]==1||x[id[j]-1]-x[id[j]-2]==1))
			j++;
		if (j>4)
			break;
		x[id[j]-1]--;
	}
	return ans;
}
int main(){
	srand(19260817);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	LL ans=1e17;
	ans=min(ans,solve());
	for (int i=1;i<=n/2;i++)
		swap(a[i],a[n-i+1]);
	ans=min(ans,solve());
	ans=min(ans,solve2());
	for (int i=1;i<=n/2;i++)
		swap(a[i],a[n-i+1]);
	ans=min(ans,solve2());
	printf("%lld",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/9251420.html

时间: 2024-10-10 03:41:05

AtCoder Regular Contest 100 (ARC100) D - Equal Cut 二分的相关文章

AtCoder Regular Contest 100 C

C - Linear Approximation题目大意:长度为n的序列,找任意一个整数b,使abs(a[i]-(i+b))的和最小.先将a[i]减去i,那么就是求a[i]-b的绝对值和最小.转换模型我们可以把a[i]看成数轴上的点,那么就是要求数轴上一个点到其他点的距离最小.曾经在蓝书上看过这个结论,b这个点就是中位数.证明一波: image.png 假设找的点是蓝色点,向左移动d个单位,则左边点到它的距离-d,右边+d,那么-4d+2d=-2d减少了2d.可见只要蓝点左右两边点数不同就不是最

AtCoder Regular Contest 100 E - Or Plus Max

一道很好的dp题 dp[K]存的是 i满足二进制1属于K二进制1位置 最大的两个Ai 这样dp[K]统计的两个数肯定满足(i | j) <= K 然后不断做 update(dp[i | (1<<j)], dp[I]) #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <

AtCoder Regular Contest 098

AtCoder Regular Contest 098 C - Attention 题意 给定一个只包含"E","W"字符串,可以花一的花费使他们互相转换.选定一个位置,使位置左边的字符都变成E,右边都变成W所需要的最小花费. 分析 这题纯粹是签到题,做两个前缀和然后直接加就可以了. #include <iostream> #include <cmath> #include <cstring> #include <cstdi

AtCoder Regular Contest 095

AtCoder Regular Contest 095 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个A和Y个B最小花费使多少. 分析: 明显的发现肯定买性价比更高的方案,分情况讨论一下,如果\(a+b<=2*c\),那么明显的先买足c到A,B中较小的一个,然后再比较一下剩下的那个的单价和\(2*c\)的大小. A[ans=] -->|a+b<=2*c| B(A*a+B*b) A -->

AtCoder Regular Contest 094

AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几次操作将三个数变为相同的数. 分析: 可以发现如果三个数的奇偶性相同直接加就可以了,对于奇偶性不同的,先把奇偶性相同的两个数都+1,然后按照相同的处理就可以了.可以证明没有更好的方案. #include <bits/stdc++.h> using namespace std; int a,b,c,

AtCoder Regular Contest 103

AtCoder Regular Contest 103 一些吐槽 参加的第一场\(ARC\):一个模拟 + 三个构造 没见过比这更令人感动的题型设置了(简直就是针对我(TAT)) . 感觉全场就我一个人\(E\)题WA了四遍才过....... C-//// 题目大意: 网址 给定一个串\(S\),要求修改一些字符,使得串满足以下条件: \(S_i = S_{i+2}\) \(S_1 \neq S_2\) . 问最少需要修改多少个字符. 题解: 无脑统计一下奇数和偶数格的每种种类. 然后在最大值和

ARC100 D - Equal Cut

D - Equal Cut Time limit : 2sec / Memory limit : 1024MB Score : 600 points Problem Statement Snuke has an integer sequence A of length N. He will make three cuts in A and divide it into four (non-empty) contiguous subsequences B,C,D and E. The positi

AtCoder Regular Contest 075 E - Meaningful Mean 树状数组求顺序对, 前缀和

题目链接: http://arc075.contest.atcoder.jp/tasks/arc075_c 题意: 给你一个序列和一个数k,求有多少对l,r,使得a[l]+a[l+1]+...+a[r]的算术平均数大于等于k 1≤N≤2×10^5 1≤K≤10^9 1≤ai≤10^9 思路: 首先对于所有数减去k,这样就不用除(r-l+1), 然后我们发现所求的就是有多少对l,r,使得sum[r]-sum[l-1] >= 0, sum是减去k之后的序列的前缀和 用树状数组对sum求有多少个顺序对

AtCoder Regular Contest 063 E:Integers on a Tree

题目传送门:https://arc063.contest.atcoder.jp/tasks/arc063_c 题目翻译 给你一个树,上面有\(k\)个点有权值,问你是否能把剩下的\(n-k\)个点全部填上权值,使得每条边链接的两个点权值相差\(1\),如果可以做到需要输出任意一组方案. 题解 我们考虑每条边权值为\(1\)或\(-1\),那么相当于黑白染色一样,所有点权值的奇偶性也都是确定的.如果与读入的\(k\)个点中某个点相冲突了就\(GG\).另外每个点的取值范围都可以转化成一段区间\([