• C


    题目链接:https://cn.vjudge.net/contest/281959#problem/C

    题目大意:中文题目

    具体思路:用网络流的思想,我们求得是最大的匹配数,那么我们按照二分图的形式去建边就可以了,加上超级源点和超级汇点,就可以用网络流跑了。

    建边的时候,我们首先把每个数进行素因子分解,看一下当前的这个数能够被分解成多少个素数,奇数个的放在一个数组里,偶数个的放在另一个数组里面(如果两个点直接能匹配的话,就需要他们两个相除之后只能剩余一个素数)。对于当前的这条边的权值,我们是按照最大流进行的,所以需要建立负边,具体的注释在代码中解释吧。

    AC代码:

      1 #include <iostream>
      2 #include<stack>
      3 #include<stdio.h>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<cstring>
      8 using namespace std;
      9 # define ll long long
     10 const int maxn = 200+100;
     11 const int maxm = 3e5+20050;
     12 const int mod = 1e9+7;
     13 const ll inf =1000000000000000ll;
     14 struct node
     15 {
     16     int to;
     17     ll cost;
     18     ll w;
     19     int nex;
     20 } edge[maxm];
     21 ll dis[maxm],prev[maxm],pree[maxm];
     22 int vis[maxm];
     23 int head[maxm],num;
     24 ll t1[maxm],t2[maxm],t3[maxm];
     25 ll tx[maxm],ty[maxm];
     26 int viss[maxm],prim[maxm],primnum,isprim[maxm*100];
     27 void prime()
     28 {
     29     for(int i=2; i<maxm; i++)
     30     {
     31         if(viss[i]==0)
     32         {
     33             viss[i]=1;
     34             prim[++primnum]=i;
     35             isprim[i]=1;
     36             for(int j=i; j<maxm; j+=i)
     37             {
     38                 viss[j]=1;
     39             }
     40         }
     41     }
     42 }
     43 bool judge(ll t1,ll t2)
     44 {
     45     if(t1==0||t2==0)
     46         return false;
     47     if(t1<t2)
     48         swap(t1,t2);
     49     if(t1%t2!=0)
     50         return false;
     51     t1/=t2;
     52 //    if(isprim[t1])
     53 //        return true;
     54 //    return false;
     55  for(int i=1;i<=primnum;i++){//判断是不是只剩下一个素数,这个地方有一个小的优化,我们看当前这个数是不是素数,只需要看到他的sqrt就可以了。
     56         if(prim[i]>=t1)break;
     57         if(t1%prim[i]==0)return 0;
     58     }
     59     return 1;
     60 }
     61 void addedge(int fr,int to,ll w,ll cost)
     62 {
     63     edge[num].to=to;
     64     edge[num].w=w;
     65     edge[num].cost=-cost;
     66     edge[num].nex=head[fr];
     67     head[fr]=num++;
     68     edge[num].to=fr;
     69     edge[num].w=0;
     70     edge[num].cost=cost;
     71     edge[num].nex=head[to];
     72     head[to]=num++;
     73 }
     74 bool spfa(int st,int ed)
     75 {
     76     memset(vis,0,sizeof(vis));
     77     memset(pree,-1,sizeof(pree));
     78     for(int i=0; i<=ed; i++)
     79         dis[i]=inf;
     80     dis[st]=0,vis[st]=1;
     81     queue<int>q;
     82     q.push(st);
     83     while(!q.empty())
     84     {
     85         int top=q.front();
     86         q.pop();
     87         vis[top]=0;
     88         for(int i=head[top]; i!=-1; i=edge[i].nex)
     89         {
     90             int tmp=edge[i].to;
     91             if(edge[i].w&&dis[tmp]>dis[top]+edge[i].cost)
     92             {
     93                 dis[tmp]=dis[top]+edge[i].cost;
     94                 pree[tmp]=top;
     95                 prev[tmp]=i;
     96                 if(vis[tmp]==0)
     97                 {
     98                     vis[tmp]=1;
     99                     q.push(tmp);
    100                 }
    101             }
    102         }
    103     }
    104     return pree[ed]!=-1;
    105 }
    106 ll mincostflow(int st,int ed)
    107 {
    108     ll ans=0;
    109     ll cost=0;
    110     while(spfa(st,ed))
    111     {
    112         ll minn=inf ;
    113         for(int i=ed; i!=st; i=pree[i])
    114         {
    115             minn=min(minn,edge[prev[i]].w);
    116         }
    117         if(cost+minn*dis[ed]<=0)//注意这个地方,我们建立的是负边。
    118         {
    119             cost+=dis[ed]*minn;
    120             ans+=minn;
    121             for(int i=ed; i!=st; i=pree[i])
    122             {
    123                 edge[prev[i]].w-=minn;
    124                 edge[prev[i]^1].w+=minn;
    125             }
    126         }
    127         else //寻找临界点
    128         {
    129             ans-=(cost/dis[ed]);
    130             return ans;
    131         }
    132     }
    133     return ans;
    134 }
    135 int main()
    136 {
    137     prime();
    138     int n;
    139     memset(head,-1,sizeof(head));
    140     scanf("%d",&n);
    141    // cout<<primnum<<endl;
    142     for(int i=1; i<=n; i++)
    143     {
    144         scanf("%lld",&t1[i]);
    145     }
    146     for(int i=1; i<=n; i++)
    147     {
    148         scanf("%lld",&t2[i]);
    149     }
    150     for(int i=1; i<=n; i++)
    151     {
    152         scanf("%lld",&t3[i]);
    153     }
    154     int num1=0,num2=0;
    155     for(int i=1; i<=n; i++)//预先处理
    156     {
    157         int tmp=t1[i],tt=0;
    158         for(int j=1; j<=primnum; j++)
    159         {
    160             while(tmp%prim[j]==0)
    161             {
    162                 tmp/=prim[j];
    163                 tt++;
    164             }
    165             if(tmp==1||tmp==0)
    166                 break;
    167         }
    168         if(tt&1)
    169             tx[++num1]=i;
    170         else
    171             ty[++num2]=i;
    172     }
    173     for(int i=1; i<=num1; i++)
    174     {
    175         for(int j=1; j<=num2; j++)
    176         {
    177             if(judge(t1[tx[i]],t1[ty[j]]))
    178             {
    179                 addedge(tx[i],ty[j],1e9,t3[tx[i]]*t3[ty[j]]);
    180             }
    181         }
    182     }
    183     for(int i=1; i<=num1; i++)
    184     {
    185         addedge(0,tx[i],t2[tx[i]],0);
    186     }
    187     for(int i=1; i<=num2; i++)
    188     {
    189         addedge(ty[i],n+1,t2[ty[i]],0);
    190     }
    191     ll ans=mincostflow(0,n+1);
    192     printf("%lld
    ",ans);
    193     return 0;
    194 }
  • 相关阅读:
    HDOJ/HDU 2560 Buildings(嗯~水题)
    HDOJ/HDU 2555 人人都能参加第30届校田径运动会了(判断加排序~)
    POJ1703Find them, Catch them
    BZOJ2303: [Apio2011]方格染色
    BZOJ2809: [Apio2012]dispatching
    POJ1611The Suspects
    BZOJ2006: [NOI2010]超级钢琴
    BZOJ2288: 【POJ Challenge】生日礼物
    BZOJ1150: [CTSC2007]数据备份Backup
    洛谷P1316 P1824
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10345919.html
Copyright © 2020-2023  润新知