• 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
  • 相关阅读:
    转 ShowSlow+Yslow页面前端性能测试环境搭建
    ORA-01843 无效的月份
    微信回复图片
    springmvc 监听器getWriter() has already been called for this response问题
    执子之手 与子偕老
    美字
    睡至三更时凡功名都成幻境 想到百年后无少长俱是古人
    oracle regexp_like介绍和例子
    Oracle中如何判断字符串是否全为数字
    ruby for in 循环中改变i的值无效
  • 原文地址:https://www.cnblogs.com/Bleacher/p/8053038.html
Copyright © 2020-2023  润新知