题解 膜拜大丹

传送门

前 5 分的暴力状压很好打
然后发现由于图的特殊性,最优方案中一定只有二元环
于是前 30 分可以二分图匹配
然后发现由于图的特殊性,可以从 n 到 1 贪心选能选的最大的 \(b\)
于是用一个 set 维护所有 \(b_i\) 就行了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
#define fir first
#define sec second
#define pb push_back
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int a[N], b[N], c[N], d[N];

namespace force{
	int dp[1<<21], ans;
	int sta[N], tot, top, now;
	vector<int> e[N];
	void dfs(int u, int s, int beg) {
		sta[++top]=u;
		now^=1<<u;
		for (auto v:e[u]) {
			if (v==beg) {
				dp[now]=max(dp[now], dp[s]+1);
			}
			else if (!(now&(1<<v))) {
				dfs(v, s, beg);
			}
		}
		--top;
		now^=1<<u;
	}
	void solve() {
		tot=n+m;
		int lim=1<<tot;
		for (int i=1; i<=n; ++i) {
			for (int j=0; j<a[i]; ++j) e[i-1].pb(j+n);
		}
		for (int i=1; i<=m; ++i) {
			for (int j=0; j<b[i]; ++j) e[i+n-1].pb(j);
		}
		for (int s=0; s<lim; ++s) {
			ans=max(ans, dp[s]);
			for (int i=0; i<tot; ++i) if (!(s&1<<i)) {
				now=s; top=0; dfs(i, s, i);
			}
		}
		cout<<ans<<endl;
	}
}

namespace task{
	ll ans;
	vector<int> buc[N];
	set<int> s;
	void solve() {
		for (int i=1; i<=m; ++i) buc[b[i]].pb(i);
		for (int i=n; i; --i) {
			for (auto it:buc[i]) s.insert(it);
			auto it=s.upper_bound(a[i]);
			if (it==s.begin()) continue;
			--it;
			while (c[i]) {
				ll t=min(c[i], d[*it]);
				ans+=t; c[i]-=t; d[*it]-=t;
				if (!d[*it]) {
					if (it==s.begin()) {s.erase(it); break;}
					else it=--s.erase(it);
				}
			}
		}
		printf("%lld\n", ans);
	}
}

signed main()
{
	freopen("worship.in", "r", stdin);
	freopen("worship.out", "w", stdout);

	n=read(); m=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	for (int i=1; i<=m; ++i) b[i]=read();
	for (int i=1; i<=n; ++i) c[i]=read();
	for (int i=1; i<=m; ++i) d[i]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-01-24 10:42  Administrator-09  阅读(10)  评论(0编辑  收藏  举报