• 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
    ",dinic());
    84     return 0;
    85 }
  • 相关阅读:
    SQLSERVER 分区分表
    SQLSERVER 执行计划
    SQL SERVER 自定义函数
    codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)
    codeforces 414A A. Mashmokh and Numbers(素数筛)
    codeforces 414B B. Mashmokh and ACM(dp)
    bzoj-1012 1012: [JSOI2008]最大数maxnumber(线段树)
    codeforces 665E E. Beautiful Subarrays(trie树)
    codeforces 667D D. World Tour(最短路)
    codeforces 667C C. Reberland Linguistics(dp)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9580706.html
Copyright © 2020-2023  润新知