题解 膜拜大丹
前 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;
}