1. 程式人生 > 實用技巧 >2020華中師範大學新生賽H--七日狂想曲

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;
}