bzoj4514: [Sdoi2016]数字配对

很沙茶很沙茶。。调了一个下午。。。结果就是下界大了。。

 

做法:可以得到一个num数组,表示这个数的质因数个数,然后若A[i]%A[j]==0并且num[i]==num[j]+1 说明它可以匹配

这样一来又可以发现按奇偶分是二分图没有环,二分答案,最大费用最大流,判断是否满流且费用大于0即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int inf=(1<<30);

int A[11000],B[11000],num[11000];
LL C[11000];
int getnum(int k)
{
    int s=0;
    for(int i=2;i*i<=k;i++)
    {
        if(k%i==0)
            while(k%i==0)k/=i,s++;
    }
    if(k>1)s++;
    return s;
}

//-----------------------------------------

int n,st,ed,S;
struct node
{
    int x,y,c,next,other;LL d;
}a[210000],e[210000];int len,last[11000],elen,elast[11000];
void eins(int x,int y,int c,LL d)
{
    int k1,k2;
    
    elen++;k1=elen;
    e[elen].x=x;e[elen].y=y;e[elen].c=c;e[elen].d=d;
    e[elen].next=elast[x];elast[x]=elen;
    
    elen++;k2=elen;
    e[elen].x=y;e[elen].y=x;e[elen].c=0;e[elen].d=-d;
    e[elen].next=elast[y];elast[y]=elen;
    
    e[k1].other=k2;
    e[k2].other=k1;
}
void composition()
{
    elen=0;memset(elast,0,sizeof(elast));
    st=n+1;ed=n+2;S=n+3;
    
    for(int i=1;i<=n;i++)
        if(num[i]%2==1)eins(st,i,B[i],0);
        else eins(i,ed,B[i],0);
    
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if((num[i]+1==num[j]&&A[j]%A[i]==0)||(num[i]==num[j]+1&&A[i]%A[j]==0))
                if(num[i]%2==1)eins(i,j,inf,C[i]*C[j]);
                else eins(j,i,inf,C[i]*C[j]);
}
//~~~~~~~~~~~~~~

void ins(int x,int y,int c,LL d)
{
    int k1,k2;
    
    len++;k1=len;
    a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
    a[len].next=last[x];last[x]=len;
    
    len++;k2=len;
    a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
    a[len].next=last[y];last[y]=len;
    
    a[k1].other=k2;
    a[k2].other=k1;
}

//-----------------------------------------

int cc;LL cost;
int list[11000];bool v[11000];
LL d[11000];
int c[11000],pre[11000];
bool spfa()
{
    for(int i=1;i<=n+4;i++)d[i]=-(LL(inf))*(LL(inf));
    d[S]=0;
    memset(c,0,sizeof(c));c[S]=inf;
    memset(pre,0,sizeof(pre));
    memset(v,false,sizeof(v));v[S]=true;
    int head=1,tail=2;list[head]=S;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(d[y]<d[x]+a[k].d&&a[k].c>0)
            {
                d[y]=d[x]+a[k].d;
                c[y]=min(c[x],a[k].c);
                pre[y]=k;
                if(v[y]==false)
                {
                    v[y]=true;
                    list[tail]=y;
                    tail++;if(tail==10100)tail=1;
                }
            }
        }
        v[x]=false;
        head++;if(head==10100)head=1;
    }
    if(d[ed]<=-(LL(inf))*(LL(inf)))return false;
    else
    {
        cc+=c[ed];
        cost+=d[ed]*c[ed];
        int y=ed;
        while(pre[y]!=0)
        {
            int k=pre[y];
            a[k].c-=c[ed];
            a[a[k].other].c+=c[ed];
            y=a[k].x;
        }
        return true;
    }
}
bool check(int mid)
{
    len=elen;
    memcpy(a,e,sizeof(a));
    memcpy(last,elast,sizeof(last));
    ins(S,st,mid,0);
    
    cc=0;cost=0;
    while(spfa()==true);
    if(cc==mid&&cost>=0)return true;
    else return false;
}
int main()
{
    freopen("pair.in","r",stdin);
    freopen("pair.out","w",stdout);
    
    int sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&A[i]),num[i]=getnum(A[i]);
    for(int i=1;i<=n;i++)scanf("%d",&B[i]),sum+=B[i];
    for(int i=1;i<=n;i++)scanf("%lld",&C[i]);
    composition();
    
    int l=0,r=sum/2,ans=0;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(check(mid)==true)
        {
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-04-19 18:52  AKCqhzdy  阅读(170)  评论(0编辑  收藏  举报