zoukankan      html  css  js  c++  java
  • bzoj4514[Sdoi2016]数字配对

    bzoj4514[Sdoi2016]数字配对

    题意:

    有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。若两个数字 ai、aj 满足ai 是 aj 的倍数且 ai/aj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。一个数字只能参与一次配对,可以不参与配对。在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

    题解:

    费用流。本题难点是每个数字只能参加一次配对,很容易建错图。正解是先对每个数字分解质因数,按照质因数个数的奇偶建二分图。原因是质因数奇数个和质因数偶数个的两个数相除的商必定不是质数,巧妙地解决了问题。在判断质数方面,如果朴素判断肯定会T,所以可以先筛法求一个质数表,判断的时候直接枚举能否整除质数。因为√109≤32000,所以质数表只要到32000就行了。不过时间复杂度我不会算,本弱太弱了!

    题解:

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <queue>
     6 #define inc(i,j,k) for(ll i=j;i<=k;i++)
     7 #define ll long long
     8 #define INF 10000000000000000
     9 using namespace std;
    10 
    11 ll p[32000],cnt,mx; bool vis1[32000];
    12 void getprime(){
    13     cnt=0; memset(vis1,0,sizeof(vis1)); inc(i,2,(ll)sqrt(mx))if(! vis1[i]){
    14         p[++cnt]=i; for(ll j=i;j<=(ll)sqrt(mx);j+=i)vis1[j]=1;
    15     }
    16 }
    17 inline bool is_prime(ll x){
    18     if(x==1)return 0;
    19     inc(i,1,cnt){if(p[i]*p[i]>x)return 1; if(x%p[i]==0)return 0;}
    20 }
    21 struct e{int f,t;ll c,w;int n;}; e es[1000000]; int ess,g[1000];
    22 inline void pe(int f,int t,ll c,ll w){
    23     es[++ess]=(e){f,t,c,w,g[f]}; g[f]=ess; es[++ess]=(e){t,f,0,-w,g[t]}; g[t]=ess;
    24 }
    25 void init(){ess=-1; memset(g,-1,sizeof(g));}
    26 queue <int> q; ll d[1000],cost,flow; int fr[1000]; bool inq[1000],vis2[1000];
    27 bool spfa(int s,int t){
    28     while(! q.empty())q.pop(); memset(vis2,0,sizeof(vis2)); memset(inq,0,sizeof(inq));
    29     q.push(s); vis2[s]=1; inq[s]=1; d[s]=0;
    30     while(! q.empty()){
    31         int x=q.front(); q.pop(); inq[x]=0;
    32         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&(!vis2[es[i].t]||d[es[i].t]<d[x]+es[i].w)){
    33             vis2[es[i].t]=1; d[es[i].t]=d[x]+es[i].w; fr[es[i].t]=i;
    34             if(!inq[es[i].t])q.push(es[i].t),inq[es[i].t]=1;
    35         }
    36     }
    37     if(!vis2[t])return 0;else return 1;
    38 }
    39 ll maxflowmaxcost(int s,int t){
    40     flow=0; cost=0;
    41     while(spfa(s,t)){
    42         ll a=INF,b=0;for(int i=t;i!=s;i=es[fr[i]].f)a=min(a,es[fr[i]].c);
    43         for(int i=t;i!=s;i=es[fr[i]].f)es[fr[i]].c-=a,es[fr[i]^1].c+=a,b+=es[fr[i]].w; cost+=b*a; flow+=a;
    44         if(cost<0){flow-=(cost%b==0?cost/b:cost/b+1); break;}
    45     }
    46     return flow;
    47 }
    48 ll a[1000],b[1000],c[1000];int n,s,t,sing[1000],doub[1000],tot,singn,doubn;
    49 int main(){
    50     scanf("%d",&n); inc(i,1,n)scanf("%lld",&a[i]),mx=max(mx,a[i]);
    51     inc(i,1,n)scanf("%lld",&b[i]); inc(i,1,n)scanf("%lld",&c[i]);
    52     getprime(); s=0; t=n+1; singn=0; doubn=0; 
    53     inc(i,1,n){
    54         int x=a[i]; tot=0; inc(j,1,cnt)if(x%p[j]==0){
    55             while(x%p[j]==0)x/=p[j],tot++; if(x==1)break;
    56         }
    57         if(tot&1)sing[++singn]=i;else doub[++doubn]=i;
    58     }
    59     init(); inc(i,1,singn)pe(s,sing[i],b[sing[i]],0); inc(i,1,doubn)pe(doub[i],t,b[doub[i]],0);
    60     inc(i,1,singn)inc(j,1,doubn)
    61         if(max(a[sing[i]],a[doub[j]])%min(a[sing[i]],a[doub[j]])==0&&is_prime(max(a[sing[i]],a[doub[j]])/min(a[sing[i]],a[doub[j]])))
    62             pe(sing[i],doub[j],INF,c[sing[i]]*c[doub[j]]);
    63     printf("%lld",maxflowmaxcost(s,t));
    64     return 0;
    65 }

    20160422

  • 相关阅读:
    Vue项目中跨域问题解决
    子网掩码
    C++的const类成员函数
    在python3中使用urllib.request编写简单的网络爬虫
    Linux 重定向输出到多个文件中
    背包问题
    hdu-1272 小希的迷宫
    SQLAlchemy 几种查询方式总结
    pycharm快捷键、常用设置、配置管理
    python3判断字典、列表、元组为空以及字典是否存在某个key的方法
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5703289.html
Copyright © 2011-2022 走看看