【bzoj4514】[Sdoi2016]数字配对 费用流

来源:互联网 发布:网络用语mmp是什么意思 编辑:程序博客网 时间:2024/06/05 09:35

题意

给n个数,他们互不相同,第i个数是a[i],有b[i]个,权值为c[i]。两个数可以配对当且仅当a[i]是a[j]的倍数且a[i]/a[j]是素数,它们配对所产生的权值是c[i]*c[j]。每次配对消耗一个数。求权值不小于0的情况下最大配对数量。

样例输入

32 4 82 200 7-1 -2 1

样例输出

4

数据范围

30%:暴力,b[i]=1
60%:c[i]=0
100%:n<=200,a[i]<=10^9,b[i]<=10^5,c[i]<=10^5


我竟然没看出来是二分图……

唯一分解后的指数之和的奇偶性可以自然而然的二分图染色,想到这点就很容易做了……

然后可配对点之间连边,流量INF。源点向指数之和是奇数的点连容量是b[i]的边,偶数的点向汇点连是b[i]的边,然后跑最大流就50分了。

顺着这个思路就很好想……既然要有权值,肯定在INF边上加上c[i]*c[j]的权值。因为跑最大费用流的时候是从费用最大的路径先增广,所以费用是单调不升的,所以在费用大于0且最小的时候的流量就是答案。

longlong坑爹。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#include<cmath>using namespace std;typedef long long LL;const int SZ = 1000010;const LL INF = 100000000000000010;int n;int head[SZ],nxt[SZ];struct edge{    int f,t;    LL d,c;}l[SZ];void build(int f,int t,LL d,LL c){    static int tot = 1;    l[++ tot].f = f; l[tot].t = t; l[tot].d = d; l[tot].c = c;    nxt[tot] = head[f];    head[f] = tot;}void insert(int f,int t,LL d,LL c){    build(f,t,d,c); build(t,f,0,-c);}bool use[SZ];LL dist[SZ];int pre[SZ];queue<int> q;bool spfa(int s,int e){    memset(dist,-128,sizeof(dist));    dist[s] = 0;    use[s] = 1;    q.push(s);    while(q.size())    {        int u = q.front(); q.pop();        use[u] = 0;        for(int i = head[u];i;i = nxt[i])        {            int v = l[i].t;            if(l[i].d && dist[v] < dist[u] + l[i].c)            {                dist[v] = dist[u] + l[i].c;                pre[v] = i;                if(!use[v])                {                    use[v] = 1;                    q.push(v);                }            }        }    }    return dist[e] < -INF ? false : true;}LL cost = 0;LL dfs(int s,int e){    LL flow = INF;    for(int i = pre[e];i;i = pre[l[i].f])        flow = min(flow,l[i].d);    if(cost + flow * dist[e] < 0) flow = -cost / dist[e];       cost += flow * dist[e];    for(int i = pre[e];i;i = pre[l[i].f])        l[i].d -= flow,l[i ^ 1].d += flow;    return flow;}LL EK(int s,int e){    LL ans = 0;    while(spfa(s,e))    {        LL tmp = dfs(s,e);        if(tmp == 0) break;        ans += tmp;    }    return ans;}int a[SZ];LL c[SZ],b[SZ];bool jojo[SZ];int zys(int n){    int x = n;    int ans = 0;    for(int i = 2;i <= sqrt(x);i ++)    {        while(n % i == 0)        {            n /= i;            ans ++;        }    }    if(n != 1)        ans ++;    return ans;}bool ispri(int x){    for(int i = 2;i <= sqrt(x);i ++)        if(x % i == 0)            return false;    return true;}int main(){    scanf("%d",&n);    for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);    for(int i = 1;i <= n;i ++) scanf("%lld",&b[i]);    for(int i = 1;i <= n;i ++) scanf("%lld",&c[i]);    for(int i = 1;i <= n;i ++) jojo[i] = zys(a[i]) % 2;    int s = n + 1,e = n + 2;    for(int i = 1;i <= n;i ++)    {        if(jojo[i] == 1)            insert(s,i,b[i],0);        else            insert(i,e,b[i],0);    }    for(int i = 1;i <= n;i ++)    {        for(int j = i + 1;j <= n;j ++)        {            if(jojo[i] ^ jojo[j])            {                if(a[i] % a[j] == 0 && ispri(a[i] / a[j]))                {                    if(jojo[i]) insert(i,j,INF,c[i] * c[j]);                    else insert(j,i,INF,c[i] * c[j]);                }                if(a[j] % a[i] == 0 && ispri(a[j] / a[i]))                {                    if(jojo[i]) insert(i,j,INF,c[i] * c[j]);                    else insert(j,i,INF,c[i] * c[j]);                                   }            }        }    }    printf("%lld\n",EK(s,e));    return 0;}/*32 4 82 200 7-1 -2 1*/
0 0
原创粉丝点击