BZOJ4514:[SDOI2016]数字配对——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4514
有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。一个数字只能参与一次配对,可以不参与配对。在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
参考洛谷题解。
这题很明显是要网络流的,且将关系图建出来之后很明显是二分图。
那么我们自然的将点归为两类,一类连S,一类连T,这样我们的边就有了方向性,然后就可以跑最大费用最大流了!
但是难受的是,我们跑的费用要求始终不低于0,这就很难办,我们简单的费用流无法胜任这个工作。
但是可以发现的是,我们spfa找可行流的时候,显然是先走大费用路径再走小费用路径,于是我们在spfa上直接跑网络流,一边更新dis,一边记录当前节点流入了多少,显然每次只能跑出来一条路径一个流因此会比原版费用流慢很多,复杂度O(玄学)反正能过。
以及我们当然不必要将二分图建出来dfs,我们记录tot[i]表示第i个数的质因子个数,则奇数为一堆偶数为一堆即可。
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int INF=1e9; const ll LINF=1e18; const int N=210; const int M=N*N*4; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int to,nxt,w; ll b; }e[M]; int n,head[N],cnt,a[N],b[N],c[N],tot[N],limit[N],pre[N]; ll dis[N]; bool vis[N]; inline void add(int u,int v,int w,ll b){ e[++cnt].to=v;e[cnt].w=w;e[cnt].b=b;e[cnt].nxt=head[u];head[u]=cnt; e[++cnt].to=u;e[cnt].w=0;e[cnt].b=-b;e[cnt].nxt=head[v];head[v]=cnt; } int suan(int k){ int ans=0; for(int i=2;i*i<=k;i++){ while(k%i==0){ ans++;k/=i; } } if(k!=1)ans++; return ans; } inline bool spfa(int s,int t,int m){ queue<int>q; memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); for(int i=1;i<=m;i++)dis[i]=-LINF; limit[s]=INF;dis[s]=0;q.push(s);vis[s]=1; while(!q.empty()){ int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to;ll b=e[i].b; if(e[i].w&&dis[v]<dis[u]+b){ dis[v]=dis[u]+b; limit[v]=min(limit[u],e[i].w); pre[v]=i; if(!vis[v]) vis[v]=1,q.push(v); } } } return dis[t]>-LINF; } inline int costflow(int S,int T,int m){ int flow=0,delta;ll ans=0; while(spfa(S,T,m)){ if(ans+dis[T]<0)break; if(dis[T]>=0)delta=limit[T]; else delta=min((ll)limit[T],ans/(-dis[T])); ans+=dis[T]*delta;flow+=delta; for(int u=T;pre[u]!=-1;u=e[pre[u]^1].to){ e[pre[u]].w-=delta;e[pre[u]^1].w+=delta; } } return flow; } int main(){ memset(head,-1,sizeof(head));cnt=-1; n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++)b[i]=read(); for(int i=1;i<=n;i++)c[i]=read(); for(int i=1;i<=n;i++)tot[i]=suan(a[i]); int S=n+1,T=S+1; for(int i=1;i<=n;i++){ if(tot[i]&1)add(S,i,b[i],0); else add(i,T,b[i],0); if(tot[i]&1){ for(int j=1;j<=n;j++){ if((a[j]%a[i]==0&&tot[i]+1==tot[j])|| (a[i]%a[j]==0&&tot[j]+1==tot[i])) add(i,j,INF,(ll)c[i]*c[j]); } } } printf("%d\n",costflow(S,T,T)); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++