bzoj4514: [Sdoi2016]数字配对(费用流)

传送门

 

ps:费用流增广的时候费用和流量打反了……调了一个多小时

每个数只能参与一次配对,那么这就是一个匹配嘛

我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数当且仅当$cnt_i=cnt_j+1$且$a_i/a_j==0$

那么我们根据$cnt_i$的奇偶性把所有数分为两类,不难发现奇偶性相同的一类是不可能互相配对的,那么这就可以变成一个二分图了

很好,那么跑一个最大费用最大流就可以了

才怪……

费用流是先保证最大流再保证最大费用,并不能保证费用大于等于0

那么我们考虑贪心。每一次spfa的时候我们都找出一条费用最大的通路,而且每一次的最长路都不会大于之前的最长路。所以我们每一次沿着最长路,在价值总和不小于0的情况下尽可能的增加流量。如果找不到通路或者继续增广会使价值总和小于0,那么就退出

可以保证这个贪心一定正确

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #include<cmath>
 7 #define int long long
 8 #define inf 0x3f3f3f3f3f3f3f3f
 9 using namespace std;
10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
11 char buf[1<<21],*p1=buf,*p2=buf;
12 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
13 inline int read(){
14     #define num ch-'0'
15     char ch;bool flag=0;int res;
16     while(!isdigit(ch=getc()))
17     (ch=='-')&&(flag=true);
18     for(res=num;isdigit(ch=getc());res=res*10+num);
19     (flag)&&(res=-res);
20     #undef num
21     return res;
22 }
23 const int N=205,M=500005;
24 int head[N],Next[M],ver[M],edge[M],flow[M],tot=1;
25 inline void add(int u,int v,int e,int f){
26     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,flow[tot]=f;
27     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=-e,flow[tot]=0;
28 }
29 int solve(int n){
30     int tot=0,s=sqrt(n);
31     for(int i=2;i<=s&&i<=n;++i)
32     while(n%i==0) ++tot,n/=i;if(n>1) ++tot;
33     return tot;
34 }
35 int dis[N],S,T,vis[N],Pre[N],ans,sum,n;
36 int a[N],b[N],c[N],cnt[N];
37 queue<int> q;
38 bool spfa(){
39     for(int i=S;i<=T;++i) vis[i]=0,dis[i]=-inf;
40     q.push(S),vis[S]=1,dis[S]=0,Pre[T]=-1;
41     while(!q.empty()){
42         int u=q.front();q.pop();vis[u]=0;
43         for(int i=head[u];i;i=Next[i]){
44             int v=ver[i];
45             if(flow[i]&&dis[v]<dis[u]+edge[i]){
46                 dis[v]=dis[u]+edge[i],Pre[v]=i;
47                 if(!vis[v]) q.push(v),vis[v]=1;
48             }
49         }
50     }
51     return ~Pre[T];
52 }
53 bool add_flow(){
54     int fl=inf,f;
55     for(int i=Pre[T];i;i=Pre[ver[i^1]])
56     cmin(fl,flow[i]);f=dis[T]*fl;
57     if(sum+f>=0){
58         sum+=f,ans+=fl;
59         for(int i=Pre[T];i;i=Pre[ver[i^1]])
60         flow[i]-=fl,flow[i^1]+=fl;return 1;
61     }
62     else return ans+=sum/(-dis[T]),0;
63 }
64 int dinic(){
65     while(spfa()&&add_flow());return ans;
66 }
67 signed main(){
68     //freopen("testdata.in","r",stdin);
69     n=read();
70     for(int i=1;i<=n;++i) a[i]=read();
71     for(int i=1;i<=n;++i) b[i]=read();
72     for(int i=1;i<=n;++i) c[i]=read();
73     S=0,T=n+1;
74     for(int i=1;i<=n;++i) cnt[i]=solve(a[i]);
75     for(int i=1;i<=n;++i)
76     cnt[i]&1?add(S,i,0,b[i]):add(i,T,0,b[i]);
77     for(int i=1;i<=n;++i)
78     if(cnt[i]&1)
79     for(int j=1;j<=n;++j)
80     if((cnt[i]+1==cnt[j]&&a[j]%a[i]==0)||
81         (cnt[j]+1==cnt[i]&&a[i]%a[j]==0))
82         add(i,j,c[i]*c[j],inf);
83     printf("%lld\n",dinic());
84     return 0;
85 }

 

posted @ 2018-09-03 20:27  bztMinamoto  阅读(153)  评论(0编辑  收藏  举报
Live2D