2020华中师范大学新生赛H--七日狂想曲

题面
这题我一看,最小费用流直接往上打,很快呀,然后无情TLE,十分正常,毕竟最小费用流复杂度\(O(nm^2)\),然后就看到了神仙题解思维,延迟贪心。

我首先打的最小费用流,是因为我发现了每个地方的每个药材去的地方不一样,那么就需要知道每个药材最合适的去处,那么最小费用流就可以模拟这个过程,但是复杂度不够。

然后是题解的思路
首先观察数据范围,可以看出最多\(O(n^2*log(n))\),这里开始构思算法。
对于某一个位置,我们需要对于其中每一个进出的药材进行路径选择,对于,每个拿出的药材,要么先拿出去,则当前这个药材转移的价值 \(val=b*(n-i+1)\),或者转移到一个固定的位置,那麽为了确定这个位置,枚举是不可能的,过不去的,但又有可能有这种情况,所以我们这里先暂时满足于\(val\)这个值,然后之后想办法改变,也就是贪心的思想,如果要到一个准确的地方,然后计算\(c*(i-j)-val_j\),这里从小往大枚举,可以保证以后枚举的j一定比i大,故\(|i-j|\)可以忽略 (这里可以这么做的前提是i转到j等价于j从i那获得)。

综上,
1:对于每一个需要转出的点,枚举当前的变化数目,然后\(val_i=min(b*(n-i+1,c*(i-j)-val_j)\),j是以前的已经得到应有数量的点,但\(c*(i-j)-val_j\)可以进行更少的操作次数,故这里可以更新.
2:同理,对于每个要获得的点\(val_j=min(a*i,c*(i-j)-val_j)\),

对于\(min()\)中后面的地方,我们可以用两个小根堆将\((-c*j-val_j)\)储存起来,这样每次取出时都可以保证\(c*(i-j)-val_j\)最小,这样复杂度就可以达到\(O(1e6*log(1e6))\),AC本题。

总结:这道题其实也算是到贪心,但很难想到,人还是太菜了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<bitset>
#include<queue>
#include<queue>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rpe(i,a,b) for(int i=a;i>=b;--i)
#define pts putchar('\n')
#define ptc putchar(' ')
typedef long long ll;
typedef unsigned long long ull;
const ll inf=1e18;;
const int maxn=1e3+9;
const int maxm=2e6+2;
const int mod=998244353;
const int base=131;

namespace IO{
    ll read(){	
		ll a=1,b=0;char c=getchar();
		while(c>'9'||c<'0'){if(c=='-')a=-1;c=getchar();} 
		while(c>='0'&&c<='9'){b=(b<<3)+(b<<1)+c-'0';c=getchar();}
		return a*b ;
	}
	void print (ll x){
		if(x<0) putchar('-'),x=-x;
		if(x>9) print(x/10);
		putchar(x%10+'0');
	} 
}
using namespace IO;

ll n;
ll a,b,c;
ll u[maxn],v[maxn];
priority_queue<ll , vector<ll> , greater<ll> >q1,q2;
ll ans=0;
int main(){
	//freopen("3.IN","r",stdin);
	n=read(),a=read(),b=read(),c=read();
	rep(i,1,n) u[i]=read();
	rep(i,1,n) v[i]=read();
	ll val;
	rep(i,1,n){
		rep(j,1,u[i]-v[i]){//向外转
			val=1LL*b*(n-i+1);
			if(!q2.empty()){
				val=min(val,q2.top()+1LL*c*i);
				q2.pop();
			}
			ans+=val;
			q1.push(-val-1LL*c*i);
		}
		rep(j,1,v[i]-u[i]){
			val=1LL*a*i;
			if(!q1.empty()){
				val=min(val,q1.top()+1LL*c*i);
				q1.pop();
			}
			ans+=val;
			q2.push(-val-1LL*c*i);
		}
	}
	print(ans);
    return 0;
}



posted @ 2020-12-28 17:49  Mr_cold  阅读(116)  评论(0)    收藏  举报