BZOJ4514 [Sdoi2016]数字配对

题解

  一开始看到这道题各种费用流的即视感。

  首先这个配对应该可以想到构建二分图模型。构建出二分图后就比较容易把关系转化为边了。

  但怎么构建呢?这个还是比较巧妙的,因为只有 小的数能整除大的数 且商为质数 的2个数才能配对。

  也就是说只有在质因子个数相差1的情况下可能配对,于是很容易很把数分成2个集合。

  然后在2个集合间靠关系建边。(具体怎么建就不阐述了)

  另外在前提是跑最大费用最大流的情况下,由于整张图的流与当前费用最大的增广流之间存在单调性,

  即随流变大,每次费用最大的增广流费用变小。(这个可以感性理解一下,主要是得意识到有这个性质)

  所以我们一次次跑spfa,跑到最大费用不能再小为止。

  答案就是最后的可行流。

代码

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 typedef long long ll;
  6 using namespace std;
  7 const ll inf=1e18;
  8 const int N=405;
  9 const int M=100000;
 10 int a[N],b[N],c[N],d[N];
 11 int n,cnt,x;
 12 struct mcmf
 13 {
 14         int l,s,t,po,cnt;
 15         int v[M],nxt[M],last[N],to[M],flow[N],pre_point[N],pre_edge[N],q[N+10];
 16         ll cost[M],f[N];
 17         bool flag[N];
 18         void clr()
 19         {
 20                 l=1;
 21                 memset(last,0,sizeof(last));
 22         }
 23         void ins(int x,int y,int z,ll c)
 24         {
 25                 nxt[++l]=last[x];
 26                 last[x]=l;
 27                 to[l]=y;
 28                 v[l]=z;
 29                 cost[l]=c;
 30         }
 31         void add(int x,int y,int z,ll c)
 32         {
 33                 ins(x,y,z,c);
 34                 ins(y,x,0,-c);
 35         }
 36         bool spfa()
 37         {
 38                 for (int i=0;i<=cnt;++i)
 39                         f[i]=-inf,
 40                         flag[i]=0,
 41                         flow[i]=0;
 42                 flow[s]=1e8;
 43                 f[s]=0;
 44                 q[1]=s;
 45                 int l,r,u,y;
 46                 l=0;r=1;
 47                 flag[s]=1;
 48                 while (l!=r)
 49                 {
 50                         l=l%N+1;
 51                         u=q[l];
 52                         for (int x=last[u];x;x=nxt[x])
 53                                 if (v[x])
 54                                 {
 55                                         y=to[x];                    
 56                                         if (f[u]+cost[x]>f[y])
 57                                         {
 58                                                 f[y]=f[u]+cost[x];
 59                                                 flow[y]=min(flow[u],v[x]);
 60                                                 pre_point[y]=u;
 61                                                 pre_edge[y]=x;                                        
 62                                                 if (flag[y])    continue;
 63                                                 flag[y]=1;
 64                                                 r=r%N+1;
 65                                                 q[r]=y;
 66                                         }
 67                                 }
 68                         flag[u]=0;
 69                 }
 70                 if (flow[t])    return 1;
 71                 else return 0;
 72         }
 73         int solve()
 74         {
 75                 ll ans=0;int tot;
 76                 while (spfa())
 77                 {
 78                         po=flow[t];                    
 79                         if (ans+f[t]*flow[t]<0)
 80                         {
 81                                 tot-=ans/f[t];
 82                                 ans+=ans/f[t]*f[t];                            
 83                                 break;
 84                         }
 85                         ans+=flow[t]*f[t];
 86                         tot+=flow[t];
 87                         for (int i=t;i!=s;i=pre_point[i])
 88                         {
 89                                 int e=pre_edge[i];
 90                                 v[e]-=po;
 91                                 v[e^1]+=po;                    
 92                         }
 93                 }
 94                 return tot;
 95         }
 96 }T;
 97 int main()
 98 {
 99         scanf("%d",&n);
100         T.clr();
101         T.s=0;
102         for (int i=1;i<=n;++i)
103         {
104                 scanf("%d",&x);
105                 a[i]=x;
106                 for (int j=2;j*j<=x;++j)
107                         while (x%j==0)
108                                 ++d[i],
109                                 x/=j;                                        
110                 if (x>1)    ++d[i];
111         }
112         T.t=n+1;
113         T.cnt=n+1;
114         for (int i=1;i<=n;++i)    scanf("%d",&b[i]);
115         for (int i=1;i<=n;++i)    scanf("%d",&c[i]);
116         for (int i=1;i<=n;++i)
117                 if (d[i]&1)    T.add(T.s,i,b[i],0);
118                 else T.add(i,T.t,b[i],0);
119         for (int i=1;i<=n;++i)
120                 for (int j=1;j<=n;++j)
121                         if (a[i]%a[j]==0 && d[i]==d[j]+1)
122                         {
123                                 if (d[i]&1)        T.add(i,j,1e8,(ll)c[i]*c[j]);
124                                 else        T.add(j,i,1e8,(ll)c[i]*c[j]);
125                         }
126         cout<<T.solve()<<endl;
127         return 0;
128 }
View Code

 

posted @ 2017-12-17 19:53 Bleacher 阅读(...) 评论(...) 编辑 收藏