![[bzoj4514]数字配对[费用流] [bzoj4514]数字配对[费用流]](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
今年SDOI的题,看到他们在做,看到过了一百多个人,然后就被虐惨啦。。。
果然考试的时候还是打不了高端算法,调了。。。几天
默默地yy了一个费用流构图:
源连所有点,配对的点连啊,所有点连汇。。。
后来罗爷爷提醒我这样子会wa,因为你无法保证所有点都没有超过B[I]次,too naive
正解是还要考虑到奇数/偶数个质数的数字,把它们变成可二分图,看出这个性质就OK了。。。
至于要保证费用下界的问题,这个。。我也不知道为什么我原来的方法不行
后来照着标程改的,加了一行memset就过了,一脸懵逼
又贡献了一道orzliyicheng没过的题,yeah~O(∩_∩)O
#include<cstdio> #include<algorithm> #include<cstring> #define mo 200000 #define value pri #define N 200000 #define vis flag #define ll long long #define inf 10000000000000LL using namespace std; ll maxn=,S,T,num,n,edgenum; ll ans,tmp; ll next[N],head[N],up[N],flag[N],vet[N],pri[N],from[N],cost[N],q[N],dis[N],a[N],b[N],c[N],f[N]; void add(int u,int v,ll w,ll c) { //printf("%d %d %lld %lld\n",u,v,w,c); edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum; pri[edgenum]=w;cost[edgenum]=c;from[edgenum]=u; } ll min(ll a,ll b) { if(a<b)return a;else return b; } bool spfa() { memset(dis,,sizeof(dis)); memset(up,,sizeof(up)); dis[S]=; vis[S]=; q[]=S; ;,tail=; while (tou<=tail) { ;//printf("query=%d\n",x); for (int i=head[x];i;i=next[i]) if (pri[i]&&dis[vet[i]]>dis[x]+cost[i]) { //printf("vet=%d\n",vet[i]); dis[vet[i]]=dis[x]+cost[i]; up[vet[i]]=i; ,tail++,q[tail%mo]=vet[i];//printf("tail=%d\n",tail); ; } tou++; } //for(int i=0;i<=T;i++)printf("%lld ",dis[i]);printf("\n"); ; ; } bool flow() { int minn=inf; for (int i=up[T];i;i=up[from[i]]) minn=min(minn,pri[i]); //printf("min==%lld %lld\n",dis[T],minn); ) { for (int i=up[T];i;i=up[from[i]]) { ;==)ee=i-; pri[i]-=minn; pri[ee]+=minn; } ans+=minn; tmp+=dis[T]*minn; ; } ;} } void dinic() { ans=;tmp=; ;i<=T;i++)flag[i]=; while (spfa()&&flow()); printf("%lld",ans); } ll calc(ll x) { ll ans=; ;i<=num;i++) ) { x/=pri[i];ans++; } )ans++;return ans; } int main() { freopen("4514.in","r",stdin); freopen("4514.out","w",stdout); scanf("%lld",&n); ;i<=n;i++)scanf("%lld",&a[i]); ;i<=n;i++)scanf("%lld",&b[i]); ;i<=n;i++)scanf("%lld",&c[i]); ;i<=maxn;i++) { )num++,pri[num]=i; ;j<=num;j++) { if(pri[j]*i>maxn)break; flag[pri[j]*i]=; )break; } } ;i<=n;i++)f[i]=calc(a[i]); S=n+,T=n+; ;i<=n;i++) ==)add(S,i,b[i],),add(i,S,,);),add(T,i,,); ;i<=n;i++) ;j<=n;j++) )) { int u,v; ==)u=i;==)v=i;else v=j; add(u,v,inf,-c[i]*c[j]);//printf("%d %d\n",c[i],c[j]); add(v,u,,c[i]*c[j]); } dinic(); }