[LibreOJ β Round #7] 小埋與遊樂場
阿新 • • 發佈:2021-09-04
一、題目
二、解法
首先思考這題怎麼修改,因為有用的位只有 \(\tt lowbit\),我們會把 \(\tt lowbit\) 小的 \(b\) 異或上 \(\tt lowbit\) 大的 \(a\) 達到讓總和減少的目的,明白這一點之後就可以做沒有元素同時在 \(A,B\) 中出現這個部分分了。
特殊情況是 \(a=b\) 可以減少的量是 \(lowbit(a)\),你可能會想討論但這東西影響確實太大了,難做。
換個思路,考慮現在問題的本質其實是一個帶權匹配模型,而且只有兩種邊:\(a=b\) 減少 \(lowbit(a)\);\(lowbit(a)>lowbit(b)\)
不知道你發現了嗎,本題的邊權值只和 \(lowbit(x)\) 有關,而只有 \(30\) 種不同的 \(lowbit\),這啟示我們可以按 \(lowbit\) 劃分等價類,還是原來費用流的圖,我們把容量修改一下就可以隨便跑了。
三、總結
劃分等價類真是重要的思想,原來它不只可以應用到 \(dp\) 上。我覺得它的本質是觀察代價和什麼量有關,然後找變數之間的平行關係,能達到優化複雜度的目的。
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <map> using namespace std; const int M = 1200005; const int N = 105; const int inf = 0x3f3f3f3f; #define ll long long int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,k,ca[N],cb[N],cc[N];ll dis[N],ans; int tot,S,T,f[N],pre[N],lst[N],flow[N],in[N]; map<int,int> mp1,mp2; struct edge { int v,c,f,next; }e[N*N]; void add(int u,int v,int c,int fl) { e[++tot]=edge{v,c,fl,f[u]},f[u]=tot; e[++tot]=edge{u,-c,0,f[v]},f[v]=tot; } int bfs() { queue<int> q; for(int i=0;i<=T;i++) dis[i]=-1e18; flow[S]=inf;pre[S]=lst[S]=dis[S]=0; q.push(S);in[S]=1; while(!q.empty()) { int u=q.front();q.pop();in[u]=0; for(int i=f[u];i;i=e[i].next) { int v=e[i].v,c=e[i].c; if(dis[v]<dis[u]+c && e[i].f>0) { dis[v]=dis[u]+c; lst[v]=i;pre[v]=u; flow[v]=min(e[i].f,flow[u]); if(!in[v]) q.push(v),in[v]=1; } } } return flow[T]>0; } void EK() { while(bfs() && k) { if(dis[T]<=0) break; int t=min(k,flow[T]); ans-=dis[T]*t; k-=t; int zy=T; while(zy!=S) { e[lst[zy]].f-=flow[T]; e[lst[zy]^1].f+=flow[T]; zy=pre[zy]; } } printf("%lld\n",ans); } int lowbit(int x) {return x&(-x);} int id(int x) {return (int)log2(lowbit(x));} int main() { n=read();tot=1; for(int i=1;i<=n;i++) { int x=read(); if(x==0) continue; ca[id(x)]++; ans+=lowbit(x); mp2[x]++; } m=read();S=70;T=71; for(int i=1;i<=m;i++) { int x=read(); if(x==0) continue; cb[id(x)]++; mp1[x]++; } k=read(); for(auto x:mp1) cc[id(x.first)]+=min(x.second,mp2[x.first]); for(int i=0;i<32;i++) { add(S,i,0,ca[i]); add(i+32,T,0,cb[i]); for(int j=0;j<i;j++) add(i,j+32,(1<<i)-(1<<j),inf); add(i,i+32,1<<i,cc[i]); } EK(); }