做题记录整理枚举2 P3745 [六省联考 2017] 期末考试(2022/9/9)
这题感觉没必要标到紫题,偏高了
难点在于:
1.想到三分
2.前缀和
(还有学长的类似廊桥分配的做法,但是那个感觉思维难度有点高)
这一题其实想到三分之后再前缀和还是挺自然的,而难点其实就是如何想到三分
题解里的图解其实就简单明了解释为什么可以三分
所以这题的启示是:对于题目的数据可以考虑使用一些形象化的方式去思考
同时这题有个技巧就是三分在l与r的差距小于5或8的时候跳出循环,在这几个值中再进行枚举,这样就可以有效避免出现三分出现的答案和正确答案差1之类的情况,可以运用到二分上,保证正确率
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
unsigned long long t[5000005],a,bb,c;
unsigned long long b[500005];
int n,m;
unsigned long long check(unsigned long long x)
{
	unsigned long long A=0,B=0,C=0; 
	unsigned long long shao=0,duo=0;
	for1(i,1,m)
	{
		if(t[i]<x)
		    shao+=x-t[i];
		else
		    duo+=t[i]-x;
	}
	for1(i,1,n)
	{
		if(b[i]<x)
	    	C+=c*(x-b[i]);
	}
	if(a>bb)
	{
		B+=bb*duo;
	}
	else{
		if(duo<=shao)
		{
			A+=duo*a;
		}
		else{
			A+=shao*a;
			B+=(duo-shao)*bb;
		}
	}
	return A+B+C;
}
int main()
{
	cin>>a>>bb>>c;
	cin>>n>>m;
	for1(i,1,n)  scanf("%lld",&b[i]);
	for1(i,1,m)  scanf("%lld",&t[i]);
	unsigned long long l=b[1],r=b[1],ans;
	for1(i,1,m)
	{
		l=min(b[i],l);
		r=max(b[i],r);
	}
    if(c==1e16){printf("%lld\n",check(l));return 0;} 
	unsigned long long mid1=l+(l+r)/3;
	unsigned long long mid2=l+((l+r)/3)*2; 
	while(r-l>8)
	{
		mid1=l+(r-l)/3;
		mid2=l+((r-l)/3)*2; 
		if(check(mid1)<check(mid2))
		{
	    	r=mid2;
		}
		else{
				l=mid1;
		}
	}
	 ans=check(l);
    for(int i=l+1;i<=r;i++)                        //在上面求出的范围内枚举时间  求出最小值即可
        ans=min(check(i),ans);
	cout<<ans<<endl;
	return 0;
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号