T1

DAY 2 TEST

【样例输入1】

3

1 1 100

50 50 50

50 50 50

【样例输出1】

133

32

样例解释:只移动100,将其移动到A中剩余两堆各16次,一共32次,此时100还剩下4,此时由于每次只能恰好移动2,最多在这一堆只能再往外运两次,无论运到哪里,都不会增加I, 所以移动32次.

【数据规模】

对于60%的数据,所有的\(A_i,B_i,C_i\)均为偶数.

对于另20%的数据,\(1 ≤ ???????? , ???????? , ???????? ≤ 2\)

对于100%的数据,\(???? ≤ 100000, 1 ≤ ???????? , ???????? , ???????? ≤ 10^9\)

20pts:枚举每一列运输完之后的最小值是奇数还是偶数。因为每个数只能是1或者2,所以步数可以直接求出来,然后比较优劣

60pts:所有的\(A_i,B_i,C_i\)都是偶数,考虑都除以二变成奇数,然后问题转化成每次移动1。

问题一很简单,就是\(sum/n\),因为不管怎样,把所有的数都变成平均值一定是最优的方案

顺着第一问,首先一个直观的想法是分别求出每一组的平均值,然后按照平均值移动。但是这样是不行的。比如:

10 10 1

1 1 10

这组数据如果按照平均值移动,要把第一组都变成7,移动6次;把第二组变成4,移动6次,一共12次

但是如果我们直接把第二组的10移动9到第一组的1,就只需要9次

不妨先把每一组的数排个序,排好序之后的序列一定是呈阶梯状上升的

那么每次肯定是要把最多的地方填到少的去,使得最小值达到下一个阶梯(比如\(A_1\)填一次达到\(A_2\)),并且保证序列单调递增的性质(也就是不改变后面的阶梯)

由于我们已经知道填补之后的\(ans\),即\(A_1+B_1+C_1\),所以我们只需要每次填补检查一下是否已经满足这个条件就行了

100pts:既有奇数,也有偶数

考虑奇数和偶数是交替的,也就是说如果拿掉2之后,答案既可能-2也可能-1

这里给出的方法是枚举每个序列最后的答案(即最小值)是奇数还是偶数

如果是奇数,那么其他的偶数至少是2,就把奇数-1,偶数-2

如果是偶数,那么其他的奇数至少是3,只把奇数-1

这就转化成了全是偶数的问题

code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<set>
#include<vector>
#include<map>
#include<queue>

#define N 300005
#define M 8000005

#define ls (t<<1)
#define rs ((t<<1)|1)
#define mid ((l+r)>>1)

#define mk make_pair
#define pb push_back
#define fi first
#define se second

using namespace std;

int i,j,m,n,p,k,A[3][N],B[N],tot;

long long Ans1=0,Ans2=0,temp1,temp2,CT;

struct Node{
		int wid,high;
}C[N];

void Wt(int c)
{
		int i;
		if (!c)
		for (i=1;i<=n;++i) if (B[i]&1) B[i]-=1;
		if (c)
		for (i=1,temp1++;i<=n;++i) if (B[i]&1) B[i]-=1; else B[i]-=2; 
		for (i=1;i<=n;++i) B[i]/=2;
		temp1+=B[1]*2;
		for (i=2;i<=n;++i) C[++tot]=(Node){i-1,B[i]-B[i-1]}; 
		for (i=2;i<=n;++i) CT+=B[i]-B[1];
}

int cmp(Node a,Node b)
{
		return a.wid<b.wid;
}

void Work(int x)
{
		int i,j; tot=0; temp1=temp2=0; CT=0;
		for (i=0;i<3;++i)
		{
			for (j=1;j<=n;++j) B[j]=A[i][j];
			Wt(x&(1<<i));
		} 
		CT/=n;
		sort(C+1,C+tot+1,cmp);
		for (i=1;i<=tot;++i) 
			if (C[i].high<CT)
			{
					temp2+=1ll*C[i].wid*C[i].high;
					CT-=C[i].high;
					temp1+=C[i].high*2;
			}	
			else
			{
					temp2+=1ll*C[i].wid*CT;
					temp1+=CT*2;
					CT=0;
			}
		if (temp1>Ans1||temp1==Ans1&&temp2<Ans2) Ans1=temp1,Ans2=temp2;
}

int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout); 
	scanf("%d",&n);
	for (i=0;i<3;++i) 
	{
		for (j=1;j<=n;++j) scanf("%d",&A[i][j]);
		sort(A[i]+1,A[i]+n+1);
	}
	for (i=0;i<8;++i) Work(i);
	printf("%lld\n%lld\n",Ans1,Ans2);
}

T2

DAY 2 TEST

DAY 2 TEST

DAY 2 TEST

90pts:直接枚举全排列,爆搜然后判断

100pts:

相关文章:

  • 2021-12-08
  • 2021-08-13
  • 2021-10-06
  • 2021-10-09
  • 2021-10-30
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-12
  • 2022-01-11
  • 2021-04-25
  • 2021-06-19
相关资源
相似解决方案